<!DOCTYPE html><html class=split lang=en-US-x-hixie><script src=../link-fixup.js defer=""></script>
<!-- Mirrored from html.spec.whatwg.org/dev/workers.html by HTTrack Website Copier/3.x [XR&CO'2014], Wed, 10 Sep 2025 08:36:28 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=utf-8" /><!-- /Added by HTTrack -->
<meta charset=utf-8><meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name=viewport><title>HTML Standard, Edition for Web Developers</title><meta content=#3c790a name=theme-color><meta content="light dark" name=color-scheme><link rel=stylesheet href=../../resources.whatwg.org/standard-shared-with-dev.css crossorigin=""><link rel=icon href=https://resources.whatwg.org/logo.svg crossorigin=""><link rel=stylesheet href=styles.css crossorigin=""><script>
   function toggleStatus(div) {
     div.parentNode.classList.toggle('wrapped');
   }
   function setLinkFragment(link) {
     link.hash = location.hash;
   }
  </script><body>
  <script async="" src=search.js></script>
  
  
  <header id=head class="head with-buttons">
   <a href=https://whatwg.org/ class=logo><img width=100 alt=WHATWG crossorigin="" class=darkmode-aware src=https://resources.whatwg.org/logo.svg height=100></a>
   
   <hgroup><h1><a rel=home href=index.html>HTML: The Living Standard</a></h1><p id=dev-edition-h2>Edition for Web Developers — Last Updated <span class=pubdate>10 September 2025</span></hgroup>
   

   <div id=search>
    <input placeholder="Search. Press '/'" autocomplete=off name=query id=query type=search>
    <ol id=results></ol>
   </div>
  </header>

  

  

  

  
  

  
  

  

  <nav><a href=web-messaging.html>← 9.3 Cross-document messaging</a> — <a href=index.html>Table of Contents</a> — <a href=worklets.html>11 Worklets →</a></nav><ol class=toc><li><a href=workers.html#workers><span class=secno>10</span> Web workers</a><ol><li><a href=workers.html#introduction-13><span class=secno>10.1</span> Introduction</a><ol><li><a href=workers.html#scope-2><span class=secno>10.1.1</span> Scope</a><li><a href=workers.html#examples-6><span class=secno>10.1.2</span> Examples</a><ol><li><a href=workers.html#a-background-number-crunching-worker><span class=secno>10.1.2.1</span> A background number-crunching worker</a><li><a href=workers.html#module-worker-example><span class=secno>10.1.2.2</span> Using a JavaScript module as a worker</a><li><a href=workers.html#shared-workers-introduction><span class=secno>10.1.2.3</span> Shared workers introduction</a><li><a href=workers.html#shared-state-using-a-shared-worker><span class=secno>10.1.2.4</span> Shared state using a shared worker</a><li><a href=workers.html#delegation><span class=secno>10.1.2.5</span> Delegation</a><li><a href=workers.html#providing-libraries><span class=secno>10.1.2.6</span> Providing libraries</a></ol><li><a href=workers.html#tutorials><span class=secno>10.1.3</span> Tutorials</a><ol><li><a href=workers.html#creating-a-dedicated-worker><span class=secno>10.1.3.1</span> Creating a dedicated worker</a><li><a href=workers.html#communicating-with-a-dedicated-worker><span class=secno>10.1.3.2</span> Communicating with a dedicated worker</a><li><a href=workers.html#shared-workers><span class=secno>10.1.3.3</span> Shared workers</a></ol></ol><li><a href=workers.html#infrastructure-2><span class=secno>10.2</span> Infrastructure</a><ol><li><a href=workers.html#the-global-scope><span class=secno>10.2.1</span> The global scope</a><ol><li><a href=workers.html#the-workerglobalscope-common-interface><span class=secno>10.2.1.1</span> The <code>WorkerGlobalScope</code> common interface</a><li><a href=workers.html#dedicated-workers-and-the-dedicatedworkerglobalscope-interface><span class=secno>10.2.1.2</span> Dedicated workers and the <code>DedicatedWorkerGlobalScope</code> interface</a><li><a href=workers.html#shared-workers-and-the-sharedworkerglobalscope-interface><span class=secno>10.2.1.3</span> Shared workers and the <code>SharedWorkerGlobalScope</code> interface</a></ol><li><a href=workers.html#worker-event-loop><span class=secno>10.2.2</span> The event loop</a><li><a href=workers.html#runtime-script-errors-2><span class=secno>10.2.3</span> Runtime script errors</a><li><a href=workers.html#creating-workers><span class=secno>10.2.4</span> Creating workers</a><ol><li><a href=workers.html#properties-present-on-both-worker-and-sharedworker><span class=secno>10.2.4.1</span> Properties present on both <code>Worker</code> and <code>SharedWorker</code></a><li><a href=workers.html#dedicated-workers-and-the-worker-interface><span class=secno>10.2.4.2</span> Dedicated workers and the <code>Worker</code> interface</a><li><a href=workers.html#shared-workers-and-the-sharedworker-interface><span class=secno>10.2.4.3</span> Shared workers and the <code>SharedWorker</code> interface</a></ol><li><a href=workers.html#navigator.hardwareconcurrency><span class=secno>10.2.5</span> Concurrent hardware capabilities</a></ol><li><a href=workers.html#apis-available-to-workers><span class=secno>10.3</span> APIs available to workers</a><ol><li><a href=workers.html#the-workernavigator-object><span class=secno>10.3.1</span> The <code>WorkerNavigator</code> interface</a><li><a href=workers.html#worker-locations><span class=secno>10.3.2</span> The <code>WorkerLocation</code> interface</a></ol></ol></ol><h2 data-lt="web worker" data-export="" id=workers data-dfn-type=dfn><span class=secno>10</span> Web workers<a href=#workers class=self-link></a></h2><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API title="Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.">Web_Workers_API</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>2+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers title="Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can perform I/O using XMLHttpRequest (although the responseXML and channel attributes are always null) or fetch (with no such restrictions). Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).">Web_Workers_API/Using_web_workers</a></div></div>

  <h3 id=introduction-13><span class=secno>10.1</span> Introduction<a href=#introduction-13 class=self-link></a></h3>

  <h4 id=scope-2><span class=secno>10.1.1</span> Scope<a href=#scope-2 class=self-link></a></h4>

  

  <p>This specification defines an API for running scripts in the background independently of any
  user interface scripts.</p>

  <p>This allows for long-running scripts that are not interrupted by scripts that respond to clicks
  or other user interactions, and allows long tasks to be executed without yielding to keep the page
  responsive.</p>

  <p>Workers (as these background scripts are called herein) are relatively heavy-weight, and are
  not intended to be used in large numbers. For example, it would be inappropriate to launch one
  worker for each pixel of a four megapixel image. The examples below show some appropriate uses of
  workers.</p>

  <p>Generally, workers are expected to be long-lived, have a high start-up performance cost, and a
  high per-instance memory cost.</p>


  <h4 id=examples-6><span class=secno>10.1.2</span> Examples<a href=#examples-6 class=self-link></a></h4>

  

  <p>There are a variety of uses that workers can be put to. The following subsections show various
  examples of this use.</p>


  <h5 id=a-background-number-crunching-worker><span class=secno>10.1.2.1</span> A background number-crunching worker<a href=#a-background-number-crunching-worker class=self-link></a></h5>

  

  <p>The simplest use of workers is for performing a computationally
  expensive task without interrupting the user interface.</p>

  <p>In this example, the main document spawns a worker to (naïvely) compute prime numbers, and
  progressively displays the most recently found prime number.</p>

  <p>The main page is as follows:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>head</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Worker example: One-core computation<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>head</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>body</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->The highest prime number discovered so far is: <c- p>&lt;</c-><c- f>output</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;result&quot;</c-><c- p>&gt;&lt;/</c-><c- f>output</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
   <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;worker.js&apos;</c-><c- p>);</c->
   worker<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;result&apos;</c-><c- p>).</c->textContent <c- o>=</c-> event<c- p>.</c->data<c- p>;</c->
   <c- p>};</c->
  <c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>body</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>html</c-><c- p>&gt;</c->
</code></pre>

  <p>The <code id=a-background-number-crunching-worker:dom-worker><a href=#dom-worker>Worker()</a></code> constructor call creates a worker and returns a
  <code id=a-background-number-crunching-worker:worker><a href=#worker>Worker</a></code> object representing that worker, which is used to communicate with the worker.
  That object's <code id=a-background-number-crunching-worker:handler-messageeventtarget-onmessage><a href=web-messaging.html#handler-messageeventtarget-onmessage>onmessage</a></code> event handler
  allows the code to receive messages from the worker.</p>

  <p>The worker itself is as follows:</p>

  <pre><code class='js'><c- a>var</c-> n <c- o>=</c-> <c- mf>1</c-><c- p>;</c->
search<c- o>:</c-> <c- k>while</c-> <c- p>(</c-><c- kc>true</c-><c- p>)</c-> <c- p>{</c->
  n <c- o>+=</c-> <c- mf>1</c-><c- p>;</c->
  <c- k>for</c-> <c- p>(</c-><c- a>var</c-> i <c- o>=</c-> <c- mf>2</c-><c- p>;</c-> i <c- o>&lt;=</c-> Math<c- p>.</c->sqrt<c- p>(</c->n<c- p>);</c-> i <c- o>+=</c-> <c- mf>1</c-><c- p>)</c->
    <c- k>if</c-> <c- p>(</c->n <c- o>%</c-> i <c- o>==</c-> <c- mf>0</c-><c- p>)</c->
     <c- k>continue</c-> search<c- p>;</c->
  <c- c1>// found a prime!</c->
  postMessage<c- p>(</c->n<c- p>);</c->
<c- p>}</c->
</code></pre>

  <p>The bulk of this code is simply an unoptimized search for a prime number. The <code id=a-background-number-crunching-worker:dom-dedicatedworkerglobalscope-postmessage><a href=#dom-dedicatedworkerglobalscope-postmessage>postMessage()</a></code> method is used to send a
  message back to the page when a prime is found.</p>

  <p><a href=../demos/workers/primes/page.html>View this example online</a>.</p>


  <h5 id=module-worker-example><span class=secno>10.1.2.2</span> Using a JavaScript module as a worker<a href=#module-worker-example class=self-link></a></h5>

  

  <p>All of our examples so far show workers that run <span>classic
  scripts</span>. Workers can instead be instantiated using <span>module
  scripts</span>, which have the usual benefits: the ability to use the JavaScript
  <code>import</code> statement to import other modules; strict mode by default; and
  top-level declarations not polluting the worker's global scope.</p>

  <p>As the <code>import</code> statement is available, the <code id=module-worker-example:dom-workerglobalscope-importscripts><a href=#dom-workerglobalscope-importscripts>importScripts()</a></code> method will automatically fail
  inside module workers.</p>

  <p>In this example, the main document uses a worker to do off-main-thread image manipulation.
  It imports the filters used from another module.</p>

  <p>The main page is as follows:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE html&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Worker example: image decoding<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->

<c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>label</c-><c- p>&gt;</c->
    Type an image URL to decode
    <c- p>&lt;</c-><c- f>input</c-> <c- e>type</c-><c- o>=</c-><c- s>&quot;url&quot;</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;image-url&quot;</c-> <c- e>list</c-><c- o>=</c-><c- s>&quot;image-list&quot;</c-><c- p>&gt;</c->
    <c- p>&lt;</c-><c- f>datalist</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;image-list&quot;</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;https://html.spec.whatwg.org/images/drawImage.png&quot;</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;https://html.spec.whatwg.org/images/robots.jpeg&quot;</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;https://html.spec.whatwg.org/images/arcTo2.png&quot;</c-><c- p>&gt;</c->
    <c- p>&lt;/</c-><c- f>datalist</c-><c- p>&gt;</c->
  <c- p>&lt;/</c-><c- f>label</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>p</c-><c- p>&gt;</c->

<c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>label</c-><c- p>&gt;</c->
    Choose a filter to apply
    <c- p>&lt;</c-><c- f>select</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;filter&quot;</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;none&quot;</c-><c- p>&gt;</c->none<c- p>&lt;/</c-><c- f>option</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;grayscale&quot;</c-><c- p>&gt;</c->grayscale<c- p>&lt;/</c-><c- f>option</c-><c- p>&gt;</c->
      <c- p>&lt;</c-><c- f>option</c-> <c- e>value</c-><c- o>=</c-><c- s>&quot;brighten&quot;</c-><c- p>&gt;</c->brighten by 20%<c- p>&lt;/</c-><c- f>option</c-><c- p>&gt;</c->
    <c- p>&lt;/</c-><c- f>select</c-><c- p>&gt;</c->
  <c- p>&lt;/</c-><c- f>label</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>p</c-><c- p>&gt;</c->

<c- p>&lt;</c-><c- f>div</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;output&quot;</c-><c- p>&gt;&lt;/</c-><c- f>div</c-><c- p>&gt;</c->

<c- p>&lt;</c-><c- f>script</c-> <c- e>type</c-><c- o>=</c-><c- s>&quot;module&quot;</c-><c- p>&gt;</c->
  <c- a>const</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- u>&quot;worker.js&quot;</c-><c- p>,</c-> <c- p>{</c-> type<c- o>:</c-> <c- u>&quot;module&quot;</c-> <c- p>});</c->
  worker<c- p>.</c->onmessage <c- o>=</c-> receiveFromWorker<c- p>;</c->

  <c- a>const</c-> url <c- o>=</c-> document<c- p>.</c->querySelector<c- p>(</c-><c- u>&quot;#image-url&quot;</c-><c- p>);</c->
  <c- a>const</c-> filter <c- o>=</c-> document<c- p>.</c->querySelector<c- p>(</c-><c- u>&quot;#filter&quot;</c-><c- p>);</c->
  <c- a>const</c-> output <c- o>=</c-> document<c- p>.</c->querySelector<c- p>(</c-><c- u>&quot;#output&quot;</c-><c- p>);</c->

  url<c- p>.</c->oninput <c- o>=</c-> updateImage<c- p>;</c->
  filter<c- p>.</c->oninput <c- o>=</c-> sendToWorker<c- p>;</c->

  <c- a>let</c-> imageData<c- p>,</c-> context<c- p>;</c->

  <c- a>function</c-> updateImage<c- p>()</c-> <c- p>{</c->
    <c- a>const</c-> img <c- o>=</c-> <c- k>new</c-> Image<c- p>();</c->
    img<c- p>.</c->src <c- o>=</c-> url<c- p>.</c->value<c- p>;</c->

    img<c- p>.</c->onload <c- o>=</c-> <c- p>()</c-> <c- p>=&gt;</c-> <c- p>{</c->
      <c- a>const</c-> canvas <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- u>&quot;canvas&quot;</c-><c- p>);</c->
      canvas<c- p>.</c->width <c- o>=</c-> img<c- p>.</c->width<c- p>;</c->
      canvas<c- p>.</c->height <c- o>=</c-> img<c- p>.</c->height<c- p>;</c->

      context <c- o>=</c-> canvas<c- p>.</c->getContext<c- p>(</c-><c- u>&quot;2d&quot;</c-><c- p>);</c->
      context<c- p>.</c->drawImage<c- p>(</c->img<c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>);</c->
      imageData <c- o>=</c-> context<c- p>.</c->getImageData<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> canvas<c- p>.</c->width<c- p>,</c-> canvas<c- p>.</c->height<c- p>);</c->

      sendToWorker<c- p>();</c->
      output<c- p>.</c->replaceChildren<c- p>(</c->canvas<c- p>);</c->
    <c- p>};</c->
  <c- p>}</c->

  <c- a>function</c-> sendToWorker<c- p>()</c-> <c- p>{</c->
    worker<c- p>.</c->postMessage<c- p>({</c-> imageData<c- p>,</c-> filter<c- o>:</c-> filter<c- p>.</c->value <c- p>});</c->
  <c- p>}</c->

  <c- a>function</c-> receiveFromWorker<c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    context<c- p>.</c->putImageData<c- p>(</c->e<c- p>.</c->data<c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>);</c->
  <c- p>}</c->
<c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
</code></pre>

  <p>The worker file is then:</p>

  <pre><code class='js'><c- k>import</c-> <c- o>*</c-> <c- k>as</c-> filters <c- k>from</c-> <c- u>&quot;./filters.js&quot;</c-><c- p>;</c->

self<c- p>.</c->onmessage <c- o>=</c-> e <c- p>=&gt;</c-> <c- p>{</c->
  <c- a>const</c-> <c- p>{</c-> imageData<c- p>,</c-> filter <c- p>}</c-> <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
  filters<c- p>[</c->filter<c- p>](</c->imageData<c- p>);</c->
  self<c- p>.</c->postMessage<c- p>(</c->imageData<c- p>,</c-> <c- p>[</c->imageData<c- p>.</c->data<c- p>.</c->buffer<c- p>]);</c->
<c- p>};</c->
</code></pre>

  <p>Which imports the file <code>filters.js</code>:</p>

  <pre><code class='js'><c- k>export</c-> <c- a>function</c-> none<c- p>()</c-> <c- p>{}</c->

<c- k>export</c-> <c- a>function</c-> grayscale<c- p>({</c-> data<c- o>:</c-> d <c- p>})</c-> <c- p>{</c->
  <c- k>for</c-> <c- p>(</c-><c- a>let</c-> i <c- o>=</c-> <c- mf>0</c-><c- p>;</c-> i <c- o>&lt;</c-> d<c- p>.</c->length<c- p>;</c-> i <c- o>+=</c-> <c- mf>4</c-><c- p>)</c-> <c- p>{</c->
    <c- a>const</c-> <c- p>[</c->r<c- p>,</c-> g<c- p>,</c-> b<c- p>]</c-> <c- o>=</c-> <c- p>[</c->d<c- p>[</c->i<c- p>],</c-> d<c- p>[</c->i <c- o>+</c-> <c- mf>1</c-><c- p>],</c-> d<c- p>[</c->i <c- o>+</c-> <c- mf>2</c-><c- p>]];</c->

    <c- c1>// CIE luminance for the RGB</c->
    <c- c1>// The human eye is bad at seeing red and blue, so we de-emphasize them.</c->
    d<c- p>[</c->i<c- p>]</c-> <c- o>=</c-> d<c- p>[</c->i <c- o>+</c-> <c- mf>1</c-><c- p>]</c-> <c- o>=</c-> d<c- p>[</c->i <c- o>+</c-> <c- mf>2</c-><c- p>]</c-> <c- o>=</c-> <c- mf>0.2126</c-> <c- o>*</c-> r <c- o>+</c-> <c- mf>0.7152</c-> <c- o>*</c-> g <c- o>+</c-> <c- mf>0.0722</c-> <c- o>*</c-> b<c- p>;</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>export</c-> <c- a>function</c-> brighten<c- p>({</c-> data<c- o>:</c-> d <c- p>})</c-> <c- p>{</c->
  <c- k>for</c-> <c- p>(</c-><c- a>let</c-> i <c- o>=</c-> <c- mf>0</c-><c- p>;</c-> i <c- o>&lt;</c-> d<c- p>.</c->length<c- p>;</c-> <c- o>++</c->i<c- p>)</c-> <c- p>{</c->
    d<c- p>[</c->i<c- p>]</c-> <c- o>*=</c-> <c- mf>1.2</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->
</code></pre>

  <p><a href=../demos/workers/modules/page.html>View this example online</a>.</p>


  <h5 id=shared-workers-introduction><span class=secno>10.1.2.3</span> Shared workers introduction<a href=#shared-workers-introduction class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker title="The SharedWorker interface represents a specific kind of worker that can be accessed from several browsing contexts, such as several windows, iframes or even workers. They implement an interface different than dedicated workers and have a different global scope, SharedWorkerGlobalScope.">SharedWorker</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>5+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android yes"><span>Firefox Android</span><span>33+</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android no"><span>Chrome Android</span><span>No</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android no"><span>Samsung Internet</span><span>4.0–5.0</span></span><span class="opera_android no"><span>Opera Android</span><span>11–14</span></span></div></div></div>

  

  <p>This section introduces shared workers using a Hello World example. Shared workers use slightly
  different APIs, since each worker can have multiple connections.</p>

  <p>This first example shows how you connect to a worker and how a worker can send a message back
  to the page when it connects to it. Received messages are displayed in a log.</p>

  <p>Here is the HTML page:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Shared workers: demo 1<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>pre</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;log&quot;</c-><c- p>&gt;</c->Log:<c- p>&lt;/</c-><c- f>pre</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
  <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;test.js&apos;</c-><c- p>);</c->
  <c- a>var</c-> log <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;log&apos;</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c-> <c- c1>// note: not worker.onmessage!</c->
    log<c- p>.</c->textContent <c- o>+=</c-> <c- t>&apos;\n&apos;</c-> <c- o>+</c-> e<c- p>.</c->data<c- p>;</c->
  <c- p>}</c->
<c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
</code></pre>

  <p>Here is the JavaScript worker:</p>

  <pre><code class='js'>onconnect <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> port <c- o>=</c-> e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>];</c->
  port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;Hello World!&apos;</c-><c- p>);</c->
<c- p>}</c->
</code></pre>

  <p><a href=../demos/workers/shared/001/test.html>View this example online</a>.</p>

  <hr>

  <p>This second example extends the first one by changing two things: first, messages are received
  using <code>addEventListener()</code> instead of an <a href=webappapis.html#event-handler-idl-attributes id=shared-workers-introduction:event-handler-idl-attributes>event handler IDL attribute</a>, and second, a message is sent <em>to</em> the
  worker, causing the worker to send another message in return. Received messages are again
  displayed in a log.</p>

  <p>Here is the HTML page:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Shared workers: demo 2<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>pre</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;log&quot;</c-><c- p>&gt;</c->Log:<c- p>&lt;/</c-><c- f>pre</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
  <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;test.js&apos;</c-><c- p>);</c->
  <c- a>var</c-> log <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;log&apos;</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    log<c- p>.</c->textContent <c- o>+=</c-> <c- t>&apos;\n&apos;</c-> <c- o>+</c-> e<c- p>.</c->data<c- p>;</c->
  <c- p>},</c-> <c- kc>false</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->start<c- p>();</c-> <c- c1>// note: need this when using addEventListener</c->
  worker<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;ping&apos;</c-><c- p>);</c->
<c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
</code></pre>

  <p>Here is the JavaScript worker:</p>

  <pre><code class='js'>onconnect <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> port <c- o>=</c-> e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>];</c->
  port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;Hello World!&apos;</c-><c- p>);</c->
  port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;pong&apos;</c-><c- p>);</c-> <c- c1>// not e.ports[0].postMessage!</c->
    <c- c1>// e.target.postMessage(&apos;pong&apos;); would work also</c->
  <c- p>}</c->
<c- p>}</c->
</code></pre>

  <p><a href=../demos/workers/shared/002/test.html>View this example online</a>.</p>

  <hr>

  <p>Finally, the example is extended to show how two pages can connect to the same worker; in this
  case, the second page is merely in an <code id=shared-workers-introduction:the-iframe-element><a href=iframe-embed-object.html#the-iframe-element>iframe</a></code> on the first page, but the same
  principle would apply to an entirely separate page in a separate <a id=shared-workers-introduction:top-level-traversable href=document-sequences.html#top-level-traversable>top-level
  traversable</a>.</p>

  <p>Here is the outer HTML page:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Shared workers: demo 3<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>pre</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;log&quot;</c-><c- p>&gt;</c->Log:<c- p>&lt;/</c-><c- f>pre</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
  <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;test.js&apos;</c-><c- p>);</c->
  <c- a>var</c-> log <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;log&apos;</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    log<c- p>.</c->textContent <c- o>+=</c-> <c- t>&apos;\n&apos;</c-> <c- o>+</c-> e<c- p>.</c->data<c- p>;</c->
  <c- p>},</c-> <c- kc>false</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->start<c- p>();</c->
  worker<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;ping&apos;</c-><c- p>);</c->
<c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>iframe</c-> <c- e>src</c-><c- o>=</c-><c- s>&quot;inner.html&quot;</c-><c- p>&gt;&lt;/</c-><c- f>iframe</c-><c- p>&gt;</c->
</code></pre>

  <p>Here is the inner HTML page:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Shared workers: demo 3 inner frame<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>pre</c-> <c- e>id</c-><c- o>=</c-><c- s>log</c-><c- p>&gt;</c->Inner log:<c- p>&lt;/</c-><c- f>pre</c-><c- p>&gt;</c->
<c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
  <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;test.js&apos;</c-><c- p>);</c->
  <c- a>var</c-> log <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;log&apos;</c-><c- p>);</c->
  worker<c- p>.</c->port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
   log<c- p>.</c->textContent <c- o>+=</c-> <c- t>&apos;\n&apos;</c-> <c- o>+</c-> e<c- p>.</c->data<c- p>;</c->
  <c- p>}</c->
<c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
</code></pre>

  <p>Here is the JavaScript worker:</p>

  <pre><code class='js'><c- a>var</c-> count <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
onconnect <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  count <c- o>+=</c-> <c- mf>1</c-><c- p>;</c->
  <c- a>var</c-> port <c- o>=</c-> e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>];</c->
  port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;Hello World! You are connection #&apos;</c-> <c- o>+</c-> count<c- p>);</c->
  port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-><c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;pong&apos;</c-><c- p>);</c->
  <c- p>}</c->
<c- p>}</c->
</code></pre>

  <p><a href=../demos/workers/shared/003/test.html>View this example online</a>.</p>


  <h5 id=shared-state-using-a-shared-worker><span class=secno>10.1.2.4</span> Shared state using a shared worker<a href=#shared-state-using-a-shared-worker class=self-link></a></h5>

  

  <p>In this example, multiple windows (viewers) can be opened that are all viewing the same map.
  All the windows share the same map information, with a single worker coordinating all the viewers.
  Each viewer can move around independently, but if they set any data on the map, all the viewers
  are updated.</p>

  <p>The main page isn't interesting, it merely provides a way to open the viewers:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>head</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Workers example: Multiviewer<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
   <c- a>function</c-> openViewer<c- p>()</c-> <c- p>{</c->
     window<c- p>.</c->open<c- p>(</c-><c- t>&apos;viewer.html&apos;</c-><c- p>);</c->
   <c- p>}</c->
  <c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>head</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>body</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;openViewer()&quot;</c-><c- p>&gt;</c->Open a new
  viewer<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->Each viewer opens in a new window. You can have as many viewers
  as you like, they all view the same data.<c- p>&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>body</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>html</c-><c- p>&gt;</c->
</code></pre>

  <p>The viewer is more involved:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>head</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Workers example: Multiviewer viewer<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
   <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;worker.js&apos;</c-><c- p>,</c-> <c- t>&apos;core&apos;</c-><c- p>);</c->

   <c- c1>// CONFIGURATION</c->
   <c- a>function</c-> configure<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     <c- k>if</c-> <c- p>(</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>4</c-><c- p>)</c-> <c- o>!=</c-> <c- t>&apos;cfg &apos;</c-><c- p>)</c-> <c- k>return</c-><c- p>;</c->
     <c- a>var</c-> name <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>).</c->split<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>,</c-> <c- mf>1</c-><c- p>)[</c-><c- mf>0</c-><c- p>];</c->
     <c- c1>// update display to mention our name is name</c->
     document<c- p>.</c->getElementsByTagName<c- p>(</c-><c- t>&apos;h1&apos;</c-><c- p>)[</c-><c- mf>0</c-><c- p>].</c->textContent <c- o>+=</c-> <c- t>&apos; &apos;</c-> <c- o>+</c-> name<c- p>;</c->
     <c- c1>// no longer need this listener</c->
     worker<c- p>.</c->port<c- p>.</c->removeEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> configure<c- p>,</c-> <c- kc>false</c-><c- p>);</c->
   <c- p>}</c->
   worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> configure<c- p>,</c-> <c- kc>false</c-><c- p>);</c->

   <c- c1>// MAP</c->
   <c- a>function</c-> paintMap<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     <c- k>if</c-> <c- p>(</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>4</c-><c- p>)</c-> <c- o>!=</c-> <c- t>&apos;map &apos;</c-><c- p>)</c-> <c- k>return</c-><c- p>;</c->
     <c- a>var</c-> data <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>).</c->split<c- p>(</c-><c- t>&apos;,&apos;</c-><c- p>);</c->
     <c- c1>// display tiles data[0] .. data[8]</c->
     <c- a>var</c-> canvas <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;map&apos;</c-><c- p>);</c->
     <c- a>var</c-> context <c- o>=</c-> canvas<c- p>.</c->getContext<c- p>(</c-><c- t>&apos;2d&apos;</c-><c- p>);</c->
     <c- k>for</c-> <c- p>(</c-><c- a>var</c-> y <c- o>=</c-> <c- mf>0</c-><c- p>;</c-> y <c- o>&lt;</c-> <c- mf>3</c-><c- p>;</c-> y <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
       <c- k>for</c-> <c- p>(</c-><c- a>var</c-> x <c- o>=</c-> <c- mf>0</c-><c- p>;</c-> x <c- o>&lt;</c-> <c- mf>3</c-><c- p>;</c-> x <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
         <c- a>var</c-> tile <c- o>=</c-> data<c- p>[</c->y <c- o>*</c-> <c- mf>3</c-> <c- o>+</c-> x<c- p>];</c->
         <c- k>if</c-> <c- p>(</c->tile <c- o>==</c-> <c- t>&apos;0&apos;</c-><c- p>)</c->
           context<c- p>.</c->fillStyle <c- o>=</c-> <c- t>&apos;green&apos;</c-><c- p>;</c->
         <c- k>else</c->
           context<c- p>.</c->fillStyle <c- o>=</c-> <c- t>&apos;maroon&apos;</c-><c- p>;</c->
         context<c- p>.</c->fillRect<c- p>(</c->x <c- o>*</c-> <c- mf>50</c-><c- p>,</c-> y <c- o>*</c-> <c- mf>50</c-><c- p>,</c-> <c- mf>50</c-><c- p>,</c-> <c- mf>50</c-><c- p>);</c->
       <c- p>}</c->
     <c- p>}</c->
   <c- p>}</c->
   worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> paintMap<c- p>,</c-> <c- kc>false</c-><c- p>);</c->

   <c- c1>// PUBLIC CHAT</c->
   <c- a>function</c-> updatePublicChat<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     <c- k>if</c-> <c- p>(</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>4</c-><c- p>)</c-> <c- o>!=</c-> <c- t>&apos;txt &apos;</c-><c- p>)</c-> <c- k>return</c-><c- p>;</c->
     <c- a>var</c-> name <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>).</c->split<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>,</c-> <c- mf>1</c-><c- p>)[</c-><c- mf>0</c-><c- p>];</c->
     <c- a>var</c-> message <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-> <c- o>+</c-> name<c- p>.</c->length <c- o>+</c-> <c- mf>1</c-><c- p>);</c->
     <c- c1>// display &quot;&lt;name&gt; message&quot; in public chat</c->
     <c- a>var</c-> public <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;public&apos;</c-><c- p>);</c->
     <c- a>var</c-> p <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;p&apos;</c-><c- p>);</c->
     <c- a>var</c-> n <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;button&apos;</c-><c- p>);</c->
     n<c- p>.</c->textContent <c- o>=</c-> <c- t>&apos;&lt;&apos;</c-> <c- o>+</c-> name <c- o>+</c-> <c- t>&apos;&gt; &apos;</c-><c- p>;</c->
     n<c- p>.</c->onclick <c- o>=</c-> <c- a>function</c-> <c- p>()</c-> <c- p>{</c-> worker<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;msg &apos;</c-> <c- o>+</c-> name<c- p>);</c-> <c- p>};</c->
     p<c- p>.</c->appendChild<c- p>(</c->n<c- p>);</c->
     <c- a>var</c-> m <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;span&apos;</c-><c- p>);</c->
     m<c- p>.</c->textContent <c- o>=</c-> message<c- p>;</c->
     p<c- p>.</c->appendChild<c- p>(</c->m<c- p>);</c->
     public<c- p>.</c->appendChild<c- p>(</c->p<c- p>);</c->
   <c- p>}</c->
   worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> updatePublicChat<c- p>,</c-> <c- kc>false</c-><c- p>);</c->

   <c- c1>// PRIVATE CHAT</c->
   <c- a>function</c-> startPrivateChat<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     <c- k>if</c-> <c- p>(</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>4</c-><c- p>)</c-> <c- o>!=</c-> <c- t>&apos;msg &apos;</c-><c- p>)</c-> <c- k>return</c-><c- p>;</c->
     <c- a>var</c-> name <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>).</c->split<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>,</c-> <c- mf>1</c-><c- p>)[</c-><c- mf>0</c-><c- p>];</c->
     <c- a>var</c-> port <c- o>=</c-> event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>];</c->
     <c- c1>// display a private chat UI</c->
     <c- a>var</c-> ul <c- o>=</c-> document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;private&apos;</c-><c- p>);</c->
     <c- a>var</c-> li <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;li&apos;</c-><c- p>);</c->
     <c- a>var</c-> h3 <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;h3&apos;</c-><c- p>);</c->
     h3<c- p>.</c->textContent <c- o>=</c-> <c- t>&apos;Private chat with &apos;</c-> <c- o>+</c-> name<c- p>;</c->
     li<c- p>.</c->appendChild<c- p>(</c->h3<c- p>);</c->
     <c- a>var</c-> div <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;div&apos;</c-><c- p>);</c->
     <c- a>var</c-> addMessage <c- o>=</c-> <c- a>function</c-><c- p>(</c->name<c- p>,</c-> message<c- p>)</c-> <c- p>{</c->
       <c- a>var</c-> p <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;p&apos;</c-><c- p>);</c->
       <c- a>var</c-> n <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;strong&apos;</c-><c- p>);</c->
       n<c- p>.</c->textContent <c- o>=</c-> <c- t>&apos;&lt;&apos;</c-> <c- o>+</c-> name <c- o>+</c-> <c- t>&apos;&gt; &apos;</c-><c- p>;</c->
       p<c- p>.</c->appendChild<c- p>(</c->n<c- p>);</c->
       <c- a>var</c-> t <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;span&apos;</c-><c- p>);</c->
       t<c- p>.</c->textContent <c- o>=</c-> message<c- p>;</c->
       p<c- p>.</c->appendChild<c- p>(</c->t<c- p>);</c->
       div<c- p>.</c->appendChild<c- p>(</c->p<c- p>);</c->
     <c- p>};</c->
     port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c->
       addMessage<c- p>(</c->name<c- p>,</c-> event<c- p>.</c->data<c- p>);</c->
     <c- p>};</c->
     li<c- p>.</c->appendChild<c- p>(</c->div<c- p>);</c->
     <c- a>var</c-> form <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;form&apos;</c-><c- p>);</c->
     <c- a>var</c-> p <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;p&apos;</c-><c- p>);</c->
     <c- a>var</c-> input <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;input&apos;</c-><c- p>);</c->
     input<c- p>.</c->size <c- o>=</c-> <c- mf>50</c-><c- p>;</c->
     p<c- p>.</c->appendChild<c- p>(</c->input<c- p>);</c->
     p<c- p>.</c->appendChild<c- p>(</c->document<c- p>.</c->createTextNode<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>));</c->
     <c- a>var</c-> button <c- o>=</c-> document<c- p>.</c->createElement<c- p>(</c-><c- t>&apos;button&apos;</c-><c- p>);</c->
     button<c- p>.</c->textContent <c- o>=</c-> <c- t>&apos;Post&apos;</c-><c- p>;</c->
     p<c- p>.</c->appendChild<c- p>(</c->button<c- p>);</c->
     form<c- p>.</c->onsubmit <c- o>=</c-> <c- a>function</c-> <c- p>()</c-> <c- p>{</c->
       port<c- p>.</c->postMessage<c- p>(</c->input<c- p>.</c->value<c- p>);</c->
       addMessage<c- p>(</c-><c- t>&apos;me&apos;</c-><c- p>,</c-> input<c- p>.</c->value<c- p>);</c->
       input<c- p>.</c->value <c- o>=</c-> <c- t>&apos;&apos;</c-><c- p>;</c->
       <c- k>return</c-> <c- kc>false</c-><c- p>;</c->
     <c- p>};</c->
     form<c- p>.</c->appendChild<c- p>(</c->p<c- p>);</c->
     li<c- p>.</c->appendChild<c- p>(</c->form<c- p>);</c->
     ul<c- p>.</c->appendChild<c- p>(</c->li<c- p>);</c->
   <c- p>}</c->
   worker<c- p>.</c->port<c- p>.</c->addEventListener<c- p>(</c-><c- t>&apos;message&apos;</c-><c- p>,</c-> startPrivateChat<c- p>,</c-> <c- kc>false</c-><c- p>);</c->

   worker<c- p>.</c->port<c- p>.</c->start<c- p>();</c->
  <c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>head</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>body</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>h1</c-><c- p>&gt;</c->Viewer<c- p>&lt;/</c-><c- f>h1</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>h2</c-><c- p>&gt;</c->Map<c- p>&lt;/</c-><c- f>h2</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>canvas</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;map&quot;</c-> <c- e>height</c-><c- o>=</c-><c- s>150</c-> <c- e>width</c-><c- o>=</c-><c- s>150</c-><c- p>&gt;&lt;/</c-><c- f>canvas</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;mov left&apos;)&quot;</c-><c- p>&gt;</c->Left<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;mov up&apos;)&quot;</c-><c- p>&gt;</c->Up<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;mov down&apos;)&quot;</c-><c- p>&gt;</c->Down<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;mov right&apos;)&quot;</c-><c- p>&gt;</c->Right<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;set 0&apos;)&quot;</c-><c- p>&gt;</c->Set 0<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>button</c-> <c- e>type</c-><c- o>=</c-><c- s>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;set 1&apos;)&quot;</c-><c- p>&gt;</c->Set 1<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
  <c- p>&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>h2</c-><c- p>&gt;</c->Public Chat<c- p>&lt;/</c-><c- f>h2</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>div</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;public&quot;</c-><c- p>&gt;&lt;/</c-><c- f>div</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>form</c-> <c- e>onsubmit</c-><c- o>=</c-><c- s>&quot;worker.port.postMessage(&apos;txt &apos; + message.value); message.value = &apos;&apos;; return false;&quot;</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->
    <c- p>&lt;</c-><c- f>input</c-> <c- e>type</c-><c- o>=</c-><c- s>&quot;text&quot;</c-> <c- e>name</c-><c- o>=</c-><c- s>&quot;message&quot;</c-> <c- e>size</c-><c- o>=</c-><c- s>&quot;50&quot;</c-><c- p>&gt;</c->
    <c- p>&lt;</c-><c- f>button</c-><c- p>&gt;</c->Post<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c->
   <c- p>&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;/</c-><c- f>form</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>h2</c-><c- p>&gt;</c->Private Chat<c- p>&lt;/</c-><c- f>h2</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>ul</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;private&quot;</c-><c- p>&gt;&lt;/</c-><c- f>ul</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>body</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>html</c-><c- p>&gt;</c->
</code></pre>

  <p>There are several key things worth noting about the way the viewer is written.</p>

  <p><strong>Multiple listeners</strong>. Instead of a single message processing function, the code
  here attaches multiple event listeners, each one performing a quick check to see if it is relevant
  for the message. In this example it doesn't make much difference, but if multiple authors wanted
  to collaborate using a single port to communicate with a worker, it would allow for independent
  code instead of changes having to all be made to a single event handling function.</p>

  <p>Registering event listeners in this way also allows you to unregister specific listeners when
  you are done with them, as is done with the <code>configure()</code> method in this
  example.</p>

  <p>Finally, the worker:</p>

  <pre><code class='js'><c- a>var</c-> nextName <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
<c- a>function</c-> getNextName<c- p>()</c-> <c- p>{</c->
  <c- c1>// this could use more friendly names</c->
  <c- c1>// but for now just return a number</c->
  <c- k>return</c-> nextName<c- o>++</c-><c- p>;</c->
<c- p>}</c->

<c- a>var</c-> map <c- o>=</c-> <c- p>[</c->
 <c- p>[</c-><c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>],</c->
 <c- p>[</c-><c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>],</c->
 <c- p>[</c-><c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>],</c->
 <c- p>[</c-><c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>],</c->
 <c- p>[</c-><c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>],</c->
 <c- p>[</c-><c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>],</c->
 <c- p>[</c-><c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>1</c-><c- p>,</c-> <c- mf>0</c-><c- p>,</c-> <c- mf>1</c-><c- p>],</c->
<c- p>];</c->

<c- a>function</c-> wrapX<c- p>(</c->x<c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->x <c- o>&lt;</c-> <c- mf>0</c-><c- p>)</c-> <c- k>return</c-> wrapX<c- p>(</c->x <c- o>+</c-> map<c- p>[</c-><c- mf>0</c-><c- p>].</c->length<c- p>);</c->
  <c- k>if</c-> <c- p>(</c->x <c- o>&gt;=</c-> map<c- p>[</c-><c- mf>0</c-><c- p>].</c->length<c- p>)</c-> <c- k>return</c-> wrapX<c- p>(</c->x <c- o>-</c-> map<c- p>[</c-><c- mf>0</c-><c- p>].</c->length<c- p>);</c->
  <c- k>return</c-> x<c- p>;</c->
<c- p>}</c->

<c- a>function</c-> wrapY<c- p>(</c->y<c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->y <c- o>&lt;</c-> <c- mf>0</c-><c- p>)</c-> <c- k>return</c-> wrapY<c- p>(</c->y <c- o>+</c-> map<c- p>.</c->length<c- p>);</c->
  <c- k>if</c-> <c- p>(</c->y <c- o>&gt;=</c-> map<c- p>[</c-><c- mf>0</c-><c- p>].</c->length<c- p>)</c-> <c- k>return</c-> wrapY<c- p>(</c->y <c- o>-</c-> map<c- p>.</c->length<c- p>);</c->
  <c- k>return</c-> y<c- p>;</c->
<c- p>}</c->

<c- a>function</c-> wrap<c- p>(</c->val<c- p>,</c-> min<c- p>,</c-> max<c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->val <c- o>&lt;</c-> min<c- p>)</c->
    <c- k>return</c-> val <c- o>+</c-> <c- p>(</c->max<c- o>-</c->min<c- p>)</c-><c- o>+</c-><c- mf>1</c-><c- p>;</c->
  <c- k>if</c-> <c- p>(</c->val <c- o>&gt;</c-> max<c- p>)</c->
    <c- k>return</c-> val <c- o>-</c-> <c- p>(</c->max<c- o>-</c->min<c- p>)</c-><c- o>-</c-><c- mf>1</c-><c- p>;</c->
  <c- k>return</c-> val<c- p>;</c->
<c- p>}</c->

<c- a>function</c-> sendMapData<c- p>(</c->viewer<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> data <c- o>=</c-> <c- t>&apos;&apos;</c-><c- p>;</c->
  <c- k>for</c-> <c- p>(</c-><c- a>var</c-> y <c- o>=</c-> viewer<c- p>.</c->y<c- o>-</c-><c- mf>1</c-><c- p>;</c-> y <c- o>&lt;=</c-> viewer<c- p>.</c->y<c- o>+</c-><c- mf>1</c-><c- p>;</c-> y <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
    <c- k>for</c-> <c- p>(</c-><c- a>var</c-> x <c- o>=</c-> viewer<c- p>.</c->x<c- o>-</c-><c- mf>1</c-><c- p>;</c-> x <c- o>&lt;=</c-> viewer<c- p>.</c->x<c- o>+</c-><c- mf>1</c-><c- p>;</c-> x <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
      <c- k>if</c-> <c- p>(</c->data <c- o>!=</c-> <c- t>&apos;&apos;</c-><c- p>)</c->
        data <c- o>+=</c-> <c- t>&apos;,&apos;</c-><c- p>;</c->
      data <c- o>+=</c-> map<c- p>[</c->wrap<c- p>(</c->y<c- p>,</c-> <c- mf>0</c-><c- p>,</c-> map<c- p>[</c-><c- mf>0</c-><c- p>].</c->length<c- o>-</c-><c- mf>1</c-><c- p>)][</c->wrap<c- p>(</c->x<c- p>,</c-> <c- mf>0</c-><c- p>,</c-> map<c- p>.</c->length<c- o>-</c-><c- mf>1</c-><c- p>)];</c->
    <c- p>}</c->
  <c- p>}</c->
  viewer<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;map &apos;</c-> <c- o>+</c-> data<c- p>);</c->
<c- p>}</c->

<c- a>var</c-> viewers <c- o>=</c-> <c- p>{};</c->
onconnect <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> name <c- o>=</c-> getNextName<c- p>();</c->
  event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->_data <c- o>=</c-> <c- p>{</c-> port<c- o>:</c-> event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>],</c-> name<c- o>:</c-> name<c- p>,</c-> x<c- o>:</c-> <c- mf>0</c-><c- p>,</c-> y<c- o>:</c-> <c- mf>0</c-><c- p>,</c-> <c- p>};</c->
  viewers<c- p>[</c->name<c- p>]</c-> <c- o>=</c-> event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->_data<c- p>;</c->
  event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->postMessage<c- p>(</c-><c- t>&apos;cfg &apos;</c-> <c- o>+</c-> name<c- p>);</c->
  event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->onmessage <c- o>=</c-> getMessage<c- p>;</c->
  sendMapData<c- p>(</c->event<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->_data<c- p>);</c->
<c- p>};</c->

<c- a>function</c-> getMessage<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  <c- k>switch</c-> <c- p>(</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>0</c-><c- p>,</c-> <c- mf>4</c-><c- p>))</c-> <c- p>{</c->
    <c- k>case</c-> <c- t>&apos;mov &apos;</c-><c- o>:</c->
      <c- a>var</c-> direction <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>);</c->
      <c- a>var</c-> dx <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
      <c- a>var</c-> dy <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
      <c- k>switch</c-> <c- p>(</c->direction<c- p>)</c-> <c- p>{</c->
        <c- k>case</c-> <c- t>&apos;up&apos;</c-><c- o>:</c-> dy <c- o>=</c-> <c- o>-</c-><c- mf>1</c-><c- p>;</c-> <c- k>break</c-><c- p>;</c->
        <c- k>case</c-> <c- t>&apos;down&apos;</c-><c- o>:</c-> dy <c- o>=</c-> <c- mf>1</c-><c- p>;</c-> <c- k>break</c-><c- p>;</c->
        <c- k>case</c-> <c- t>&apos;left&apos;</c-><c- o>:</c-> dx <c- o>=</c-> <c- o>-</c-><c- mf>1</c-><c- p>;</c-> <c- k>break</c-><c- p>;</c->
        <c- k>case</c-> <c- t>&apos;right&apos;</c-><c- o>:</c-> dx <c- o>=</c-> <c- mf>1</c-><c- p>;</c-> <c- k>break</c-><c- p>;</c->
      <c- p>}</c->
      event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->x <c- o>=</c-> wrapX<c- p>(</c->event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->x <c- o>+</c-> dx<c- p>);</c->
      event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->y <c- o>=</c-> wrapY<c- p>(</c->event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->y <c- o>+</c-> dy<c- p>);</c->
      sendMapData<c- p>(</c->event<c- p>.</c->target<c- p>.</c->_data<c- p>);</c->
      <c- k>break</c-><c- p>;</c->
    <c- k>case</c-> <c- t>&apos;set &apos;</c-><c- o>:</c->
      <c- a>var</c-> value <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>);</c->
      map<c- p>[</c->event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->y<c- p>][</c->event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->x<c- p>]</c-> <c- o>=</c-> value<c- p>;</c->
      <c- k>for</c-> <c- p>(</c-><c- a>var</c-> viewer <c- k>in</c-> viewers<c- p>)</c->
        sendMapData<c- p>(</c->viewers<c- p>[</c->viewer<c- p>]);</c->
      <c- k>break</c-><c- p>;</c->
    <c- k>case</c-> <c- t>&apos;txt &apos;</c-><c- o>:</c->
      <c- a>var</c-> name <c- o>=</c-> event<c- p>.</c->target<c- p>.</c->_data<c- p>.</c->name<c- p>;</c->
      <c- a>var</c-> message <c- o>=</c-> event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>);</c->
      <c- k>for</c-> <c- p>(</c-><c- a>var</c-> viewer <c- k>in</c-> viewers<c- p>)</c->
        viewers<c- p>[</c->viewer<c- p>].</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;txt &apos;</c-> <c- o>+</c-> name <c- o>+</c-> <c- t>&apos; &apos;</c-> <c- o>+</c-> message<c- p>);</c->
      <c- k>break</c-><c- p>;</c->
    <c- k>case</c-> <c- t>&apos;msg &apos;</c-><c- o>:</c->
      <c- a>var</c-> party1 <c- o>=</c-> event<c- p>.</c->target<c- p>.</c->_data<c- p>;</c->
      <c- a>var</c-> party2 <c- o>=</c-> viewers<c- p>[</c->event<c- p>.</c->data<c- p>.</c->substr<c- p>(</c-><c- mf>4</c-><c- p>).</c->split<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>,</c-> <c- mf>1</c-><c- p>)[</c-><c- mf>0</c-><c- p>]];</c->
      <c- k>if</c-> <c- p>(</c->party2<c- p>)</c-> <c- p>{</c->
        <c- a>var</c-> channel <c- o>=</c-> <c- k>new</c-> MessageChannel<c- p>();</c->
        party1<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;msg &apos;</c-> <c- o>+</c-> party2<c- p>.</c->name<c- p>,</c-> <c- p>[</c->channel<c- p>.</c->port1<c- p>]);</c->
        party2<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;msg &apos;</c-> <c- o>+</c-> party1<c- p>.</c->name<c- p>,</c-> <c- p>[</c->channel<c- p>.</c->port2<c- p>]);</c->
      <c- p>}</c->
      <c- k>break</c-><c- p>;</c->
  <c- p>}</c->
<c- p>}</c->
</code></pre>

  <p><strong>Connecting to multiple pages</strong>. The script uses the <code id=shared-state-using-a-shared-worker:handler-sharedworkerglobalscope-onconnect><a href=#handler-sharedworkerglobalscope-onconnect>onconnect</a></code> event listener to listen for
  multiple connections.</p>

  <p><strong>Direct channels</strong>. When the worker receives a "msg" message from one viewer
  naming another viewer, it sets up a direct connection between the two, so that the two viewers can
  communicate directly without the worker having to proxy all the messages.</p>

  <p><a href=../demos/workers/multiviewer/page.html>View this example online</a>.</p>


  <h5 id=delegation><span class=secno>10.1.2.5</span> Delegation<a href=#delegation class=self-link></a></h5>

  

  <p>With multicore CPUs becoming prevalent, one way to obtain better performance is to split
  computationally expensive tasks amongst multiple workers. In this example, a computationally
  expensive task that is to be performed for every number from 1 to 10,000,000 is farmed out to ten
  subworkers.</p>

  <p>The main page is as follows, it just reports the result:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>head</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Worker example: Multicore computation<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>head</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>body</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;</c->Result: <c- p>&lt;</c-><c- f>output</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;result&quot;</c-><c- p>&gt;&lt;/</c-><c- f>output</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
   <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;worker.js&apos;</c-><c- p>);</c->
   worker<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c->
     document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;result&apos;</c-><c- p>).</c->textContent <c- o>=</c-> event<c- p>.</c->data<c- p>;</c->
   <c- p>};</c->
  <c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>body</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>html</c-><c- p>&gt;</c->
</code></pre>

  <p>The worker itself is as follows:</p>

  <pre><code class='js'><c- c1>// settings</c->
<c- a>var</c-> num_workers <c- o>=</c-> <c- mf>10</c-><c- p>;</c->
<c- a>var</c-> items_per_worker <c- o>=</c-> <c- mf>1000000</c-><c- p>;</c->

<c- c1>// start the workers</c->
<c- a>var</c-> result <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
<c- a>var</c-> pending_workers <c- o>=</c-> num_workers<c- p>;</c->
<c- k>for</c-> <c- p>(</c-><c- a>var</c-> i <c- o>=</c-> <c- mf>0</c-><c- p>;</c-> i <c- o>&lt;</c-> num_workers<c- p>;</c-> i <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;core.js&apos;</c-><c- p>);</c->
  worker<c- p>.</c->postMessage<c- p>(</c->i <c- o>*</c-> items_per_worker<c- p>);</c->
  worker<c- p>.</c->postMessage<c- p>((</c->i<c- o>+</c-><c- mf>1</c-><c- p>)</c-> <c- o>*</c-> items_per_worker<c- p>);</c->
  worker<c- p>.</c->onmessage <c- o>=</c-> storeResult<c- p>;</c->
<c- p>}</c->

<c- c1>// handle the results</c->
<c- a>function</c-> storeResult<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  result <c- o>+=</c-> <c- mf>1</c-><c- o>*</c->event<c- p>.</c->data<c- p>;</c->
  pending_workers <c- o>-=</c-> <c- mf>1</c-><c- p>;</c->
  <c- k>if</c-> <c- p>(</c->pending_workers <c- o>&lt;=</c-> <c- mf>0</c-><c- p>)</c->
    postMessage<c- p>(</c->result<c- p>);</c-> <c- c1>// finished!</c->
<c- p>}</c->
</code></pre>

  <p>It consists of a loop to start the subworkers, and then a handler
  that waits for all the subworkers to respond.</p>

  <p>The subworkers are implemented as follows:</p>

  <pre><code class='js'><c- a>var</c-> start<c- p>;</c->
onmessage <c- o>=</c-> getStart<c- p>;</c->
<c- a>function</c-> getStart<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  start <c- o>=</c-> <c- mf>1</c-><c- o>*</c->event<c- p>.</c->data<c- p>;</c->
  onmessage <c- o>=</c-> getEnd<c- p>;</c->
<c- p>}</c->

<c- a>var</c-> end<c- p>;</c->
<c- a>function</c-> getEnd<c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  end <c- o>=</c-> <c- mf>1</c-><c- o>*</c->event<c- p>.</c->data<c- p>;</c->
  onmessage <c- o>=</c-> <c- kc>null</c-><c- p>;</c->
  work<c- p>();</c->
<c- p>}</c->

<c- a>function</c-> work<c- p>()</c-> <c- p>{</c->
  <c- a>var</c-> result <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
  <c- k>for</c-> <c- p>(</c-><c- a>var</c-> i <c- o>=</c-> start<c- p>;</c-> i <c- o>&lt;</c-> end<c- p>;</c-> i <c- o>+=</c-> <c- mf>1</c-><c- p>)</c-> <c- p>{</c->
    <c- c1>// perform some complex calculation here</c->
    result <c- o>+=</c-> <c- mf>1</c-><c- p>;</c->
  <c- p>}</c->
  postMessage<c- p>(</c->result<c- p>);</c->
  close<c- p>();</c->
<c- p>}</c->
</code></pre>

  <p>They receive two numbers in two events, perform the computation for the range of numbers thus
  specified, and then report the result back to the parent.</p>

  <p><a href=../demos/workers/multicore/page.html>View this example online</a>.</p>


  <h5 id=providing-libraries><span class=secno>10.1.2.6</span> Providing libraries<a href=#providing-libraries class=self-link></a></h5>

  

  <p>Suppose that a cryptography library is made available that provides three tasks:</p>

  <dl><dt>Generate a public/private key pair<dd>Takes a port, on which it will send two messages, first the public key and then the private
   key.<dt>Given a plaintext and a public key, return the corresponding ciphertext<dd>Takes a port, to which any number of messages can be sent, the first giving the public key,
   and the remainder giving the plaintext, each of which is encrypted and then sent on that same
   channel as the ciphertext. The user can close the port when it is done encrypting content.<dt>Given a ciphertext and a private key, return the corresponding plaintext<dd>Takes a port, to which any number of messages can be sent, the first giving the private key,
   and the remainder giving the ciphertext, each of which is decrypted and then sent on that same
   channel as the plaintext. The user can close the port when it is done decrypting content.</dl>

  <p>The library itself is as follows:</p>

  <pre><code class='js'><c- a>function</c-> handleMessage<c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;genkeys&quot;</c-><c- p>)</c->
    genkeys<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  <c- k>else</c-> <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;encrypt&quot;</c-><c- p>)</c->
    encrypt<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  <c- k>else</c-> <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;decrypt&quot;</c-><c- p>)</c->
    decrypt<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
<c- p>}</c->

<c- a>function</c-> genkeys<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> keys <c- o>=</c-> _generateKeyPair<c- p>();</c->
  p<c- p>.</c->postMessage<c- p>(</c->keys<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  p<c- p>.</c->postMessage<c- p>(</c->keys<c- p>[</c-><c- mf>1</c-><c- p>]);</c->
<c- p>}</c->

<c- a>function</c-> encrypt<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> key<c- p>,</c-> state <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
  p<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- k>if</c-> <c- p>(</c->state <c- o>==</c-> <c- mf>0</c-><c- p>)</c-> <c- p>{</c->
      key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
      state <c- o>=</c-> <c- mf>1</c-><c- p>;</c->
    <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
      p<c- p>.</c->postMessage<c- p>(</c->_encrypt<c- p>(</c->key<c- p>,</c-> e<c- p>.</c->data<c- p>));</c->
    <c- p>}</c->
  <c- p>};</c->
<c- p>}</c->

<c- a>function</c-> decrypt<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> key<c- p>,</c-> state <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
  p<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- k>if</c-> <c- p>(</c->state <c- o>==</c-> <c- mf>0</c-><c- p>)</c-> <c- p>{</c->
      key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
      state <c- o>=</c-> <c- mf>1</c-><c- p>;</c->
    <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
      p<c- p>.</c->postMessage<c- p>(</c->_decrypt<c- p>(</c->key<c- p>,</c-> e<c- p>.</c->data<c- p>));</c->
    <c- p>}</c->
  <c- p>};</c->
<c- p>}</c->

<c- c1>// support being used as a shared worker as well as a dedicated worker</c->
<c- k>if</c-> <c- p>(</c-><c- t>&apos;onmessage&apos;</c-> <c- k>in</c-> <c- k>this</c-><c- p>)</c-> <c- c1>// dedicated worker</c->
  onmessage <c- o>=</c-> handleMessage<c- p>;</c->
<c- k>else</c-> <c- c1>// shared worker</c->
  onconnect <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c-> e<c- p>.</c->port<c- p>.</c->onmessage <c- o>=</c-> handleMessage<c- p>;</c-> <c- p>}</c->


<c- c1>// the &quot;crypto&quot; functions:</c->

<c- a>function</c-> _generateKeyPair<c- p>()</c-> <c- p>{</c->
  <c- k>return</c-> <c- p>[</c->Math<c- p>.</c->random<c- p>(),</c-> Math<c- p>.</c->random<c- p>()];</c->
<c- p>}</c->

<c- a>function</c-> _encrypt<c- p>(</c->k<c- p>,</c-> s<c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- t>&apos;encrypted-&apos;</c-> <c- o>+</c-> k <c- o>+</c-> <c- t>&apos; &apos;</c-> <c- o>+</c-> s<c- p>;</c->
<c- p>}</c->

<c- a>function</c-> _decrypt<c- p>(</c->k<c- p>,</c-> s<c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> s<c- p>.</c->substr<c- p>(</c->s<c- p>.</c->indexOf<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>)</c-><c- o>+</c-><c- mf>1</c-><c- p>);</c->
<c- p>}</c->
</code></pre>

  <p>Note that the crypto functions here are just stubs and don't do real cryptography.</p>

  <p>This library could be used as follows:</p>

  <pre><code class='html'><c- cp>&lt;!DOCTYPE HTML&gt;</c->
<c- p>&lt;</c-><c- f>html</c-> <c- e>lang</c-><c- o>=</c-><c- s>&quot;en&quot;</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>head</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>meta</c-> <c- e>charset</c-><c- o>=</c-><c- s>&quot;utf-8&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>title</c-><c- p>&gt;</c->Worker example: Crypto library<c- p>&lt;/</c-><c- f>title</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>script</c-><c- p>&gt;</c->
   <c- a>const</c-> cryptoLib <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;libcrypto-v1.js&apos;</c-><c- p>);</c-> <c- c1>// or could use &apos;libcrypto-v2.js&apos;</c->
   <c- a>function</c-> startConversation<c- p>(</c->source<c- p>,</c-> message<c- p>)</c-> <c- p>{</c->
     <c- a>const</c-> messageChannel <c- o>=</c-> <c- k>new</c-> MessageChannel<c- p>();</c->
     source<c- p>.</c->postMessage<c- p>(</c->message<c- p>,</c-> <c- p>[</c->messageChannel<c- p>.</c->port2<c- p>]);</c->
     <c- k>return</c-> messageChannel<c- p>.</c->port1<c- p>;</c->
   <c- p>}</c->
   <c- a>function</c-> getKeys<c- p>()</c-> <c- p>{</c->
     <c- a>let</c-> state <c- o>=</c-> <c- mf>0</c-><c- p>;</c->
     startConversation<c- p>(</c->cryptoLib<c- p>,</c-> <c- u>&quot;genkeys&quot;</c-><c- p>).</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
       <c- k>if</c-> <c- p>(</c->state <c- o>===</c-> <c- mf>0</c-><c- p>)</c->
         document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;public&apos;</c-><c- p>).</c->value <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
       <c- k>else</c-> <c- k>if</c-> <c- p>(</c->state <c- o>===</c-> <c- mf>1</c-><c- p>)</c->
         document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;private&apos;</c-><c- p>).</c->value <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
       state <c- o>+=</c-> <c- mf>1</c-><c- p>;</c->
     <c- p>};</c->
   <c- p>}</c->
   <c- a>function</c-> enc<c- p>()</c-> <c- p>{</c->
     <c- a>const</c-> port <c- o>=</c-> startConversation<c- p>(</c->cryptoLib<c- p>,</c-> <c- u>&quot;encrypt&quot;</c-><c- p>);</c->
     port<c- p>.</c->postMessage<c- p>(</c->document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;public&apos;</c-><c- p>).</c->value<c- p>);</c->
     port<c- p>.</c->postMessage<c- p>(</c->document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;input&apos;</c-><c- p>).</c->value<c- p>);</c->
     port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
       document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;input&apos;</c-><c- p>).</c->value <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
       port<c- p>.</c->close<c- p>();</c->
     <c- p>};</c->
   <c- p>}</c->
   <c- a>function</c-> dec<c- p>()</c-> <c- p>{</c->
     <c- a>const</c-> port <c- o>=</c-> startConversation<c- p>(</c->cryptoLib<c- p>,</c-> <c- u>&quot;decrypt&quot;</c-><c- p>);</c->
     port<c- p>.</c->postMessage<c- p>(</c->document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;private&apos;</c-><c- p>).</c->value<c- p>);</c->
     port<c- p>.</c->postMessage<c- p>(</c->document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;input&apos;</c-><c- p>).</c->value<c- p>);</c->
     port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
       document<c- p>.</c->getElementById<c- p>(</c-><c- t>&apos;input&apos;</c-><c- p>).</c->value <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
       port<c- p>.</c->close<c- p>();</c->
     <c- p>};</c->
   <c- p>}</c->
  <c- p>&lt;/</c-><c- f>script</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>style</c-><c- p>&gt;</c->
   <c- f>textarea</c-> <c- p>{</c-> <c- k>display</c-><c- p>:</c-> <c- kc>block</c-><c- p>;</c-> <c- p>}</c->
  <c- p>&lt;/</c-><c- f>style</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>head</c-><c- p>&gt;</c->
 <c- p>&lt;</c-><c- f>body</c-> <c- e>onload</c-><c- o>=</c-><c- s>&quot;getKeys()&quot;</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>fieldset</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>legend</c-><c- p>&gt;</c->Keys<c- p>&lt;/</c-><c- f>legend</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>label</c-><c- p>&gt;</c->Public Key: <c- p>&lt;</c-><c- f>textarea</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;public&quot;</c-><c- p>&gt;&lt;/</c-><c- f>textarea</c-><c- p>&gt;&lt;/</c-><c- f>label</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
   <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>label</c-><c- p>&gt;</c->Private Key: <c- p>&lt;</c-><c- f>textarea</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;private&quot;</c-><c- p>&gt;&lt;/</c-><c- f>textarea</c-><c- p>&gt;&lt;/</c-><c- f>label</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;/</c-><c- f>fieldset</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>label</c-><c- p>&gt;</c->Input: <c- p>&lt;</c-><c- f>textarea</c-> <c- e>id</c-><c- o>=</c-><c- s>&quot;input&quot;</c-><c- p>&gt;&lt;/</c-><c- f>textarea</c-><c- p>&gt;&lt;/</c-><c- f>label</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
  <c- p>&lt;</c-><c- f>p</c-><c- p>&gt;&lt;</c-><c- f>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;enc()&quot;</c-><c- p>&gt;</c->Encrypt<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;</c-> <c- p>&lt;</c-><c- f>button</c-> <c- e>onclick</c-><c- o>=</c-><c- s>&quot;dec()&quot;</c-><c- p>&gt;</c->Decrypt<c- p>&lt;/</c-><c- f>button</c-><c- p>&gt;&lt;/</c-><c- f>p</c-><c- p>&gt;</c->
 <c- p>&lt;/</c-><c- f>body</c-><c- p>&gt;</c->
<c- p>&lt;/</c-><c- f>html</c-><c- p>&gt;</c->
</code></pre>

  <p>A later version of the API, though, might want to offload all the crypto work onto subworkers.
  This could be done as follows:</p>

  <pre><code class='js'><c- a>function</c-> handleMessage<c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;genkeys&quot;</c-><c- p>)</c->
    genkeys<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  <c- k>else</c-> <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;encrypt&quot;</c-><c- p>)</c->
    encrypt<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  <c- k>else</c-> <c- k>if</c-> <c- p>(</c->e<c- p>.</c->data <c- o>==</c-> <c- u>&quot;decrypt&quot;</c-><c- p>)</c->
    decrypt<c- p>(</c->e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
<c- p>}</c->

<c- a>function</c-> genkeys<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> generator <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;libcrypto-v2-generator.js&apos;</c-><c- p>);</c->
  generator<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;&apos;</c-><c- p>,</c-> <c- p>[</c->p<c- p>]);</c->
<c- p>}</c->

<c- a>function</c-> encrypt<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  p<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- a>var</c-> key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
    <c- a>var</c-> encryptor <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;libcrypto-v2-encryptor.js&apos;</c-><c- p>);</c->
    encryptor<c- p>.</c->postMessage<c- p>(</c->key<c- p>,</c-> <c- p>[</c->p<c- p>]);</c->
  <c- p>};</c->
<c- p>}</c->

<c- a>function</c-> encrypt<c- p>(</c->p<c- p>)</c-> <c- p>{</c->
  p<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- a>var</c-> key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
    <c- a>var</c-> decryptor <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;libcrypto-v2-decryptor.js&apos;</c-><c- p>);</c->
    decryptor<c- p>.</c->postMessage<c- p>(</c->key<c- p>,</c-> <c- p>[</c->p<c- p>]);</c->
  <c- p>};</c->
<c- p>}</c->

<c- c1>// support being used as a shared worker as well as a dedicated worker</c->
<c- k>if</c-> <c- p>(</c-><c- t>&apos;onmessage&apos;</c-> <c- k>in</c-> <c- k>this</c-><c- p>)</c-> <c- c1>// dedicated worker</c->
  onmessage <c- o>=</c-> handleMessage<c- p>;</c->
<c- k>else</c-> <c- c1>// shared worker</c->
  onconnect <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c-> e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->onmessage <c- o>=</c-> handleMessage <c- p>};</c->
</code></pre>

  <p>The little subworkers would then be as follows.</p>

  <p>For generating key pairs:</p>

  <pre><code class='js'>onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> k <c- o>=</c-> _generateKeyPair<c- p>();</c->
  e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->postMessage<c- p>(</c->k<c- p>[</c-><c- mf>0</c-><c- p>]);</c->
  e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->postMessage<c- p>(</c->k<c- p>[</c-><c- mf>1</c-><c- p>]);</c->
  close<c- p>();</c->
<c- p>}</c->

<c- a>function</c-> _generateKeyPair<c- p>()</c-> <c- p>{</c->
  <c- k>return</c-> <c- p>[</c->Math<c- p>.</c->random<c- p>(),</c-> Math<c- p>.</c->random<c- p>()];</c->
<c- p>}</c->
</code></pre>

  <p>For encrypting:</p>

  <pre><code class='js'>onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
  e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- a>var</c-> s <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
    postMessage<c- p>(</c->_encrypt<c- p>(</c->key<c- p>,</c-> s<c- p>));</c->
  <c- p>}</c->
<c- p>}</c->

<c- a>function</c-> _encrypt<c- p>(</c->k<c- p>,</c-> s<c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- t>&apos;encrypted-&apos;</c-> <c- o>+</c-> k <c- o>+</c-> <c- t>&apos; &apos;</c-> <c- o>+</c-> s<c- p>;</c->
<c- p>}</c->
</code></pre>

  <p>For decrypting:</p>

  <pre><code class='js'>onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> key <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
  e<c- p>.</c->ports<c- p>[</c-><c- mf>0</c-><c- p>].</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->e<c- p>)</c-> <c- p>{</c->
    <c- a>var</c-> s <c- o>=</c-> e<c- p>.</c->data<c- p>;</c->
    postMessage<c- p>(</c->_decrypt<c- p>(</c->key<c- p>,</c-> s<c- p>));</c->
  <c- p>}</c->
<c- p>}</c->

<c- a>function</c-> _decrypt<c- p>(</c->k<c- p>,</c-> s<c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> s<c- p>.</c->substr<c- p>(</c->s<c- p>.</c->indexOf<c- p>(</c-><c- t>&apos; &apos;</c-><c- p>)</c-><c- o>+</c-><c- mf>1</c-><c- p>);</c->
<c- p>}</c->
</code></pre>

  <p>Notice how the users of the API don't have to even know that this is happening — the API
  hasn't changed; the library can delegate to subworkers without changing its API, even though it is
  accepting data using message channels.</p>

  <p><a href=../demos/workers/crypto/page.html>View this example online</a>.</p>


  <h4 id=tutorials><span class=secno>10.1.3</span> Tutorials<a href=#tutorials class=self-link></a></h4>

  <h5 id=creating-a-dedicated-worker><span class=secno>10.1.3.1</span> Creating a dedicated worker<a href=#creating-a-dedicated-worker class=self-link></a></h5>

  

  <p>Creating a worker requires a URL to a JavaScript file. The <code id=creating-a-dedicated-worker:dom-worker><a href=#dom-worker>Worker()</a></code> constructor is invoked with the URL to that file as its only
  argument; a worker is then created and returned:</p>

  <pre><code class='js'><c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;helper.js&apos;</c-><c- p>);</c-></code></pre>

  <p>If you want your worker script to be interpreted as a <span>module script</span> instead of
  the default <span>classic script</span>, you need to use a slightly different signature:</p>

  <pre><code class='js'><c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> Worker<c- p>(</c-><c- t>&apos;helper.mjs&apos;</c-><c- p>,</c-> <c- p>{</c-> type<c- o>:</c-> <c- u>&quot;module&quot;</c-> <c- p>});</c-></code></pre>


  <h5 id=communicating-with-a-dedicated-worker><span class=secno>10.1.3.2</span> Communicating with a dedicated worker<a href=#communicating-with-a-dedicated-worker class=self-link></a></h5>

  

  <p>Dedicated workers use <code>MessagePort</code> objects behind the scenes, and thus support all
  the same features, such as sending structured data, transferring binary data, and transferring
  other ports.</p>

  <p>To receive messages from a dedicated worker, use the <code id=communicating-with-a-dedicated-worker:handler-messageeventtarget-onmessage><a href=web-messaging.html#handler-messageeventtarget-onmessage>onmessage</a></code> <a href=webappapis.html#event-handler-idl-attributes id=communicating-with-a-dedicated-worker:event-handler-idl-attributes>event handler IDL attribute</a> on the <code id=communicating-with-a-dedicated-worker:worker><a href=#worker>Worker</a></code> object:</p>

  <pre><code class='js'>worker<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>};</c-></code></pre>

  <p>You can also use the <code id=communicating-with-a-dedicated-worker:dom-eventtarget-addeventlistener><a data-x-internal=dom-eventtarget-addeventlistener href=https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener>addEventListener()</a></code>
  method.</p>

  <p class=note>The implicit <code>MessagePort</code> used by dedicated workers has its <span>port
  message queue</span> implicitly enabled when it is created, so there is no equivalent to the
  <code>MessagePort</code> interface's <code id=communicating-with-a-dedicated-worker:dom-messageport-start><a href=web-messaging.html#dom-messageport-start>start()</a></code> method on
  the <code id=communicating-with-a-dedicated-worker:worker-2><a href=#worker>Worker</a></code> interface.</p>

  <p>To <em>send</em> data to a worker, use the <code id=communicating-with-a-dedicated-worker:dom-worker-postmessage><a href=#dom-worker-postmessage>postMessage()</a></code> method. Structured data can be sent over this
  communication channel. To send <code id=communicating-with-a-dedicated-worker:idl-arraybuffer><a data-x-internal=idl-arraybuffer href=https://webidl.spec.whatwg.org/#idl-ArrayBuffer>ArrayBuffer</a></code> objects
  efficiently (by transferring them rather than cloning them), list them in an array in the second
  argument.</p>

  <pre><code class='js'>worker<c- p>.</c->postMessage<c- p>({</c->
  operation<c- o>:</c-> <c- t>&apos;find-edges&apos;</c-><c- p>,</c->
  input<c- o>:</c-> buffer<c- p>,</c-> <c- c1>// an ArrayBuffer object</c->
  threshold<c- o>:</c-> <c- mf>0.6</c-><c- p>,</c->
<c- p>},</c-> <c- p>[</c->buffer<c- p>]);</c-></code></pre>

  <p>To receive a message inside the worker, the <code id=communicating-with-a-dedicated-worker:handler-messageeventtarget-onmessage-2><a href=web-messaging.html#handler-messageeventtarget-onmessage>onmessage</a></code> <a href=webappapis.html#event-handler-idl-attributes id=communicating-with-a-dedicated-worker:event-handler-idl-attributes-2>event handler IDL attribute</a> is used.</p>

  <pre><code class='js'>onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>};</c-></code></pre>

  <p>You can again also use the <code id=communicating-with-a-dedicated-worker:dom-eventtarget-addeventlistener-2><a data-x-internal=dom-eventtarget-addeventlistener href=https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener>addEventListener()</a></code> method.</p>

  <p>In either case, the data is provided in the event object's <code id=communicating-with-a-dedicated-worker:dom-messageevent-data><a href=comms.html#dom-messageevent-data>data</a></code> attribute.</p>

  <p>To send messages back, you again use <code id=communicating-with-a-dedicated-worker:dom-dedicatedworkerglobalscope-postmessage><a href=#dom-dedicatedworkerglobalscope-postmessage>postMessage()</a></code>. It supports the
  structured data in the same manner.</p>

  <pre><code class='js'>postMessage<c- p>(</c->event<c- p>.</c->data<c- p>.</c->input<c- p>,</c-> <c- p>[</c->event<c- p>.</c->data<c- p>.</c->input<c- p>]);</c-> <c- c1>// transfer the buffer back</c-></code></pre>


  <h5 id=shared-workers data-dfn-type=dfn data-lt="shared worker"><span class=secno>10.1.3.3</span> Shared workers<a href=#shared-workers class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker title="The SharedWorker interface represents a specific kind of worker that can be accessed from several browsing contexts, such as several windows, iframes or even workers. They implement an interface different than dedicated workers and have a different global scope, SharedWorkerGlobalScope.">SharedWorker</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>5+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android yes"><span>Firefox Android</span><span>33+</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android no"><span>Chrome Android</span><span>No</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android no"><span>Samsung Internet</span><span>4.0–5.0</span></span><span class="opera_android no"><span>Opera Android</span><span>11–14</span></span></div></div></div>

  

  <p>Shared workers are identified by the URL of the script used to create it, optionally with an
  explicit name. The name allows multiple instances of a particular shared worker to be started.</p>

  <p>Shared workers are scoped by <a id=shared-workers:concept-origin href=browsers.html#concept-origin>origin</a>. Two different sites using the same names will
  not collide. However, if a page tries to use the same shared worker name as another page on the
  same site, but with a different script URL, it will fail.</p>

  <p>Creating shared workers is done using the <code id=shared-workers:dom-sharedworker><a href=#dom-sharedworker>SharedWorker()</a></code>
  constructor. This constructor takes the URL to the script to use for its first argument, and the
  name of the worker, if any, as the second argument.</p>

  <pre><code class='js'><c- a>var</c-> worker <c- o>=</c-> <c- k>new</c-> SharedWorker<c- p>(</c-><c- t>&apos;service.js&apos;</c-><c- p>);</c-></code></pre>

  <p>Communicating with shared workers is done with explicit <code>MessagePort</code> objects. The
  object returned by the <code id=shared-workers:dom-sharedworker-2><a href=#dom-sharedworker>SharedWorker()</a></code> constructor holds a
  reference to the port on its <code id=shared-workers:dom-sharedworker-port><a href=#dom-sharedworker-port>port</a></code> attribute.</p>

  <pre><code class='js'>worker<c- p>.</c->port<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>};</c->
worker<c- p>.</c->port<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;some message&apos;</c-><c- p>);</c->
worker<c- p>.</c->port<c- p>.</c->postMessage<c- p>({</c-> foo<c- o>:</c-> <c- t>&apos;structured&apos;</c-><c- p>,</c-> bar<c- o>:</c-> <c- p>[</c-><c- t>&apos;data&apos;</c-><c- p>,</c-> <c- t>&apos;also&apos;</c-><c- p>,</c-> <c- t>&apos;possible&apos;</c-><c- p>]});</c-></code></pre>

  <p>Inside the shared worker, new clients of the worker are announced using the <code id=shared-workers:event-workerglobalscope-connect><a href=indices.html#event-workerglobalscope-connect>connect</a></code> event. The port for the new client is
  given by the event object's <code id=shared-workers:dom-messageevent-source><a href=comms.html#dom-messageevent-source>source</a></code> attribute.</p>

  <pre><code class='js'>onconnect <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c->
  <c- a>var</c-> newPort <c- o>=</c-> event<c- p>.</c->source<c- p>;</c->
  <c- c1>// set up a listener</c->
  newPort<c- p>.</c->onmessage <c- o>=</c-> <c- a>function</c-> <c- p>(</c->event<c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>};</c->
  <c- c1>// send a message back to the port</c->
  newPort<c- p>.</c->postMessage<c- p>(</c-><c- t>&apos;ready!&apos;</c-><c- p>);</c-> <c- c1>// can also send structured data, of course</c->
<c- p>};</c-></code></pre>




  <h3 id=infrastructure-2><span class=secno>10.2</span> Infrastructure<a href=#infrastructure-2 class=self-link></a></h3>

  <p>This standard defines two kinds of workers: dedicated workers, and shared workers. Dedicated
  workers, once created, are linked to their creator, but message ports can be used to communicate
  from a dedicated worker to multiple other browsing contexts or workers. Shared workers, on the
  other hand, are named, and once created any script running in the same <a id=infrastructure-2:concept-origin href=browsers.html#concept-origin>origin</a> can
  obtain a reference to that worker and communicate with it. <cite>Service Workers</cite> defines a
  third kind. <a href=references.html#refsSW>[SW]</a></p>


  <h4 id=the-global-scope><span class=secno>10.2.1</span> The global scope<a href=#the-global-scope class=self-link></a></h4>

  <p>The global scope is the "inside" of a worker.</p>

  <h5 id=the-workerglobalscope-common-interface><span class=secno>10.2.1.1</span> The <code id=workerglobalscope>WorkerGlobalScope</code> common interface<a href=#the-workerglobalscope-common-interface class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope title="The WorkerGlobalScope interface of the Web Workers API is an interface representing the scope of any worker. Workers have no browsing context; this scope contains the information usually conveyed by Window objects — in this case event handlers, the console or the associated WorkerNavigator object. Each WorkerGlobalScope has its own event loop.">WorkerGlobalScope</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div>

  

  <p><code id=the-workerglobalscope-common-interface:workerglobalscope><a href=#workerglobalscope>WorkerGlobalScope</a></code> serves as the base class for specific types of worker global
  scope objects, including <code id=the-workerglobalscope-common-interface:dedicatedworkerglobalscope><a href=#dedicatedworkerglobalscope>DedicatedWorkerGlobalScope</a></code>,
  <code id=the-workerglobalscope-common-interface:sharedworkerglobalscope><a href=#sharedworkerglobalscope>SharedWorkerGlobalScope</a></code>, and <code id=the-workerglobalscope-common-interface:serviceworkerglobalscope><a data-x-internal=serviceworkerglobalscope href=https://w3c.github.io/ServiceWorker/#serviceworkerglobalscope>ServiceWorkerGlobalScope</a></code>.</p>

  

  <dl class=domintro><dt><code><var>workerGlobal</var>.<span id=dom-workerglobalscope-self>self</span></code><dd>Returns <var>workerGlobal</var>.<dt><code><var>workerGlobal</var>.<span id=dom-workerglobalscope-location>location</span></code><dd>Returns <var>workerGlobal</var>'s <code id=the-workerglobalscope-common-interface:workerlocation><a href=#workerlocation>WorkerLocation</a></code> object.<dt><code><var>workerGlobal</var>.<span id=dom-worker-navigator>navigator</span></code><dd>Returns <var>workerGlobal</var>'s <code id=the-workerglobalscope-common-interface:workernavigator><a href=#workernavigator>WorkerNavigator</a></code> object.<dt><code><var>workerGlobal</var>.<span id=dom-workerglobalscope-importscripts>importScripts</span>(...<var>urls</var>)</code><dd>Fetches each <a id=the-workerglobalscope-common-interface:url href=https://url.spec.whatwg.org/#concept-url data-x-internal=url>URL</a> in <var>urls</var>, executes them one-by-one in the order they
   are passed, and then returns (or throws if something went amiss).</dl>

  

  <p>The following are the <a id=the-workerglobalscope-common-interface:event-handlers href=webappapis.html#event-handlers>event handlers</a> (and their corresponding <span>event handler event types</span>)  supported,
  as <a id=the-workerglobalscope-common-interface:event-handler-idl-attributes href=webappapis.html#event-handler-idl-attributes>event handler IDL attributes</a>, by objects implementing the
  <code id=the-workerglobalscope-common-interface:workerglobalscope-2><a href=#workerglobalscope>WorkerGlobalScope</a></code> interface:</p>

  <table><thead><tr><th><a href=webappapis.html#event-handlers id=the-workerglobalscope-common-interface:event-handlers-2>Event handler</a> <th><span>Event handler event type</span>
   <tbody><tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-onerror data-dfn-type=attribute><code>onerror</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/error_event title="The error event of the WorkerGlobalScope interface fires when an error occurs in the worker.">WorkerGlobalScope/error_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>11.5+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android unknown"><span>Opera Android</span><span>?</span></span></div></div></div><td> <code id=the-workerglobalscope-common-interface:event-error><a href=indices.html#event-error>error</a></code>
    <tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-onlanguagechange data-dfn-type=attribute><code>onlanguagechange</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/languagechange_event title="The languagechange event is fired at the global scope object when the user's preferred language changes.">WorkerGlobalScope/languagechange_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>74+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>11.5+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android yes"><span>WebView Android</span><span>37+</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android unknown"><span>Opera Android</span><span>?</span></span></div></div></div><td> <code id=the-workerglobalscope-common-interface:event-languagechange><a href=indices.html#event-languagechange>languagechange</a></code> 
    <tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-onoffline data-dfn-type=attribute><code>onoffline</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/offline_event title="The offline event of the WorkerGlobalScope fires when the device loses connection to the internet.">WorkerGlobalScope/offline_event</a><div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>8+</span></span><span class="chrome no"><span>Chrome</span><span>No</span></span><hr><span class="opera unknown"><span>Opera</span><span>?</span></span><span class="edge_blink no"><span>Edge</span><span>No</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios unknown"><span>Safari iOS</span><span>?</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android unknown"><span>Opera Android</span><span>?</span></span></div></div></div><td> <code id=the-workerglobalscope-common-interface:event-offline><a href=indices.html#event-offline>offline</a></code> 
    <tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-ononline data-dfn-type=attribute><code>ononline</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/online_event title="The online event of the WorkerGlobalScope fires when the device reconnects to the internet.">WorkerGlobalScope/online_event</a><div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>8+</span></span><span class="chrome no"><span>Chrome</span><span>No</span></span><hr><span class="opera unknown"><span>Opera</span><span>?</span></span><span class="edge_blink no"><span>Edge</span><span>No</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios unknown"><span>Safari iOS</span><span>?</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android unknown"><span>Opera Android</span><span>?</span></span></div></div></div><td> <code id=the-workerglobalscope-common-interface:event-online><a href=indices.html#event-online>online</a></code> 
    <tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-onrejectionhandled data-dfn-type=attribute><code>onrejectionhandled</code></dfn> <td> <code id=the-workerglobalscope-common-interface:event-rejectionhandled><a href=indices.html#event-rejectionhandled>rejectionhandled</a></code>
    <tr><td><dfn data-dfn-for=WorkerGlobalScope id=handler-workerglobalscope-onunhandledrejection data-dfn-type=attribute><code>onunhandledrejection</code></dfn> <td> <code id=the-workerglobalscope-common-interface:event-unhandledrejection><a href=indices.html#event-unhandledrejection>unhandledrejection</a></code>
  </table>


  <h5 id=dedicated-workers-and-the-dedicatedworkerglobalscope-interface><span class=secno>10.2.1.2</span> Dedicated workers and the <code id=dedicatedworkerglobalscope>DedicatedWorkerGlobalScope</code> interface<a href=#dedicated-workers-and-the-dedicatedworkerglobalscope-interface class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope title="The DedicatedWorkerGlobalScope object (the Worker global scope) is accessible through the self keyword. Some additional global functions, namespaces objects, and constructors, not typically associated with the worker global scope, but available on it, are listed in the JavaScript Reference. See also: Functions available to workers.">DedicatedWorkerGlobalScope</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div>

  

  <p><code id=dedicated-workers-and-the-dedicatedworkerglobalscope-interface:dedicatedworkerglobalscope><a href=#dedicatedworkerglobalscope>DedicatedWorkerGlobalScope</a></code> objects have an associated <dfn id=inside-port>inside port</dfn> (a
  <code>MessagePort</code>). This port is part of a channel that is set up when the worker is
  created, but it is not exposed.</p>

  <dl class=domintro><dt><code><var>dedicatedWorkerGlobal</var>.<span id=dom-dedicatedworkerglobalscope-name>name</span></code><dd><p>Returns <var>dedicatedWorkerGlobal</var>'s <span>name</span>, i.e. the value given to the
   <code id=dedicated-workers-and-the-dedicatedworkerglobalscope-interface:worker><a href=#worker>Worker</a></code> constructor. Primarily useful for debugging.<dt><code><var>dedicatedWorkerGlobal</var>.<span id=dom-dedicatedworkerglobalscope-postmessage>postMessage</span>(<var>message</var> [, <var>transfer</var> ])</code><dt><code><var>dedicatedWorkerGlobal</var>.<span id=dom-dedicatedworkerglobalscope-postmessage-options>postMessage</span>(<var>message</var> [, { <span>transfer</span> } ])</code><dd><p>Clones <var>message</var> and transmits it to the <code id=dedicated-workers-and-the-dedicatedworkerglobalscope-interface:worker-2><a href=#worker>Worker</a></code> object associated
   with <var>dedicatedWorkerGlobal</var>. <var>transfer</var> can be passed as a list of objects
   that are to be transferred rather than cloned.<dt><code><var>dedicatedWorkerGlobal</var>.<span id=dom-dedicatedworkerglobalscope-close>close</span>()</code><dd><p>Aborts <var>dedicatedWorkerGlobal</var>.</dl>

  

  <h5 id=shared-workers-and-the-sharedworkerglobalscope-interface><span class=secno>10.2.1.3</span> Shared workers and the <code id=sharedworkerglobalscope>SharedWorkerGlobalScope</code> interface<a href=#shared-workers-and-the-sharedworkerglobalscope-interface class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope title="The SharedWorkerGlobalScope object (the SharedWorker global scope) is accessible through the self keyword. Some additional global functions, namespaces objects, and constructors, not typically associated with the worker global scope, but available on it, are listed in the JavaScript Reference. See the complete list of functions available to workers.">SharedWorkerGlobalScope</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android yes"><span>WebView Android</span><span>37+</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div>

  

  

  <p>Shared workers receive message ports through <code id=shared-workers-and-the-sharedworkerglobalscope-interface:event-workerglobalscope-connect><a href=indices.html#event-workerglobalscope-connect>connect</a></code> events on their <code id=shared-workers-and-the-sharedworkerglobalscope-interface:sharedworkerglobalscope><a href=#sharedworkerglobalscope>SharedWorkerGlobalScope</a></code> object for each
  connection.</p>

  <dl class=domintro><dt><code><var>sharedWorkerGlobal</var>.<span id=dom-sharedworkerglobalscope-name>name</span></code><dd><p>Returns <var>sharedWorkerGlobal</var>'s <span>name</span>, i.e. the value given to the
   <code id=shared-workers-and-the-sharedworkerglobalscope-interface:sharedworker><a href=#sharedworker>SharedWorker</a></code> constructor. Multiple <code id=shared-workers-and-the-sharedworkerglobalscope-interface:sharedworker-2><a href=#sharedworker>SharedWorker</a></code> objects can correspond
   to the same shared worker (and <code id=shared-workers-and-the-sharedworkerglobalscope-interface:sharedworkerglobalscope-2><a href=#sharedworkerglobalscope>SharedWorkerGlobalScope</a></code>), by reusing the same
   name.<dt><code><var>sharedWorkerGlobal</var>.<span id=dom-sharedworkerglobalscope-close>close</span>()</code><dd><p>Aborts <var>sharedWorkerGlobal</var>.</dl>

  

  <p>The following are the <a id=shared-workers-and-the-sharedworkerglobalscope-interface:event-handlers href=webappapis.html#event-handlers>event handlers</a> (and their corresponding <span>event handler event types</span>)  supported,
  as <a id=shared-workers-and-the-sharedworkerglobalscope-interface:event-handler-idl-attributes href=webappapis.html#event-handler-idl-attributes>event handler IDL attributes</a>, by objects implementing the
  <code id=shared-workers-and-the-sharedworkerglobalscope-interface:sharedworkerglobalscope-3><a href=#sharedworkerglobalscope>SharedWorkerGlobalScope</a></code> interface:</p>

  <table><thead><tr><th><a href=webappapis.html#event-handlers id=shared-workers-and-the-sharedworkerglobalscope-interface:event-handlers-2>Event handler</a> <th><span>Event handler event type</span>
   <tbody><tr><td><dfn data-dfn-for=SharedWorkerGlobalScope id=handler-sharedworkerglobalscope-onconnect data-dfn-type=attribute><code>onconnect</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorkerGlobalScope/connect_event title="The connect event is fired in shared workers at their SharedWorkerGlobalScope when a new client connects.">SharedWorkerGlobalScope/connect_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android yes"><span>WebView Android</span><span>37+</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div><td> <code id=shared-workers-and-the-sharedworkerglobalscope-interface:event-workerglobalscope-connect-2><a href=indices.html#event-workerglobalscope-connect>connect</a></code>
  </table>



  <h4 id=worker-event-loop><span class=secno>10.2.2</span> The event loop<a href=#worker-event-loop class=self-link></a></h4>

  <p>A <a id=worker-event-loop:worker-event-loop-2 href=webappapis.html#worker-event-loop-2>worker event loop</a>'s <span>task queues</span> only have
  events, callbacks, and networking activity as <span>tasks</span>.</p>

  <p>Each <code id=worker-event-loop:workerglobalscope><a href=#workerglobalscope>WorkerGlobalScope</a></code> object has a <dfn data-dfn-for=WorkerGlobalScope id=dom-workerglobalscope-closing data-export="">closing</dfn> flag,  initially
  false, but which can get set to true <span>when the worker is requested to close</span>.</p>

  <p>Once the <code id=worker-event-loop:workerglobalscope-2><a href=#workerglobalscope>WorkerGlobalScope</a></code>'s <a href=#dom-workerglobalscope-closing id=worker-event-loop:dom-workerglobalscope-closing>closing</a> flag is set to true, the <a id=worker-event-loop:event-loop href=webappapis.html#event-loop>event
  loop</a>'s <span>task queues</span>  discard any
  further <span>tasks</span> that would be added to them (tasks already on the
  queue are unaffected except where otherwise specified). Effectively, once the <a href=#dom-workerglobalscope-closing id=worker-event-loop:dom-workerglobalscope-closing-2>closing</a> flag is true, timers stop firing,
  notifications for all pending background operations are dropped, etc.</p>



  


  <h4 id=runtime-script-errors-2><span class=secno>10.2.3</span> Runtime script errors<a href=#runtime-script-errors-2 class=self-link></a></h4>

  <p>Whenever an uncaught runtime script error occurs in one of the worker's scripts, if the error
  did not occur while handling a previous script error, the user agent will <span>report</span> it for the worker's <code id=runtime-script-errors-2:workerglobalscope><a href=#workerglobalscope>WorkerGlobalScope</a></code> object.</p>


  <h4 id=creating-workers><span class=secno>10.2.4</span> Creating workers<a href=#creating-workers class=self-link></a></h4>

  
  <h5 id=properties-present-on-both-worker-and-sharedworker><span class=secno>10.2.4.1</span> Properties present on both <code id=properties-present-on-both-worker-and-sharedworker:worker><a href=#worker>Worker</a></code> and <code id=properties-present-on-both-worker-and-sharedworker:sharedworker><a href=#sharedworker>SharedWorker</a></code><a href=#properties-present-on-both-worker-and-sharedworker class=self-link></a></h5>

  

  <p>The following are the <a id=properties-present-on-both-worker-and-sharedworker:event-handlers href=webappapis.html#event-handlers>event handlers</a> (and their corresponding <span>event handler event types</span>)  supported,
  as <a id=properties-present-on-both-worker-and-sharedworker:event-handler-idl-attributes href=webappapis.html#event-handler-idl-attributes>event handler IDL attributes</a>, by <span><code id=properties-present-on-both-worker-and-sharedworker:worker-2><a href=#worker>Worker</a></code> and
  <code id=properties-present-on-both-worker-and-sharedworker:sharedworker-2><a href=#sharedworker>SharedWorker</a></code> objects</span>:</p>

  <table><thead><tr><th><a href=webappapis.html#event-handlers id=properties-present-on-both-worker-and-sharedworker:event-handlers-2>Event handler</a> <th><span>Event handler event type</span>
   <tbody><tr><td><dfn data-dfn-for=AbstractWorker id=handler-abstractworker-onerror data-dfn-type=attribute><code>onerror</code></dfn> <div class="mdn-anno wrapped before"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/error_event title="The error event fires whenever an error occurs in the service worker.">ServiceWorker/error_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>44+</span></span><span class="safari yes"><span>Safari</span><span>11.1+</span></span><span class="chrome yes"><span>Chrome</span><span>40+</span></span><hr><span class="opera unknown"><span>Opera</span><span>?</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>17+</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios unknown"><span>Safari iOS</span><span>?</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android unknown"><span>Opera Android</span><span>?</span></span></div></div><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/error_event title="The error event of the SharedWorker interface fires when an error occurs in the worker.">SharedWorker/error_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>5+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android yes"><span>Firefox Android</span><span>33+</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android no"><span>Chrome Android</span><span>No</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android no"><span>Samsung Internet</span><span>4.0–5.0</span></span><span class="opera_android no"><span>Opera Android</span><span>11–14</span></span></div></div><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/Worker/error_event title="The error event of the Worker interface fires when an error occurs in the worker.">Worker/error_event</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div><td> <code id=properties-present-on-both-worker-and-sharedworker:event-error><a href=indices.html#event-error>error</a></code>
  </table>


  


  <h5 id=dedicated-workers-and-the-worker-interface><span class=secno>10.2.4.2</span> Dedicated workers and the <code id=worker>Worker</code> interface<a href=#dedicated-workers-and-the-worker-interface class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/Worker title="The Worker interface of the Web Workers API represents a background task that can be created via script, which can send messages back to its creator.">Worker</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>2+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>11+</span></span></div></div></div>

  

  <dl class=domintro><dt><code><var>worker</var> = new <span id=dom-worker>Worker</span>(<var>scriptURL</var> [, <var>options</var> ])</code><dd>
    <p>Returns a new <code id=dedicated-workers-and-the-worker-interface:worker><a href=#worker>Worker</a></code> object. <var>scriptURL</var> will be fetched and executed
    in the background, creating a new global environment for which <var>worker</var> represents the
    communication channel.</p>

    <p><var>options</var> can contain the following values:</p>

    <ul><li><p><code id=dom-workeroptions-name>name</code> can be used to define the <span>name</span> of that global environment, primarily for
     debugging purposes.<li><p><code id=dom-workeroptions-type>type</code> can be used to load the new
     global environment from <var>scriptURL</var> as a JavaScript module, by setting it to the value
     "<code>module</code>".<li><p><code id=dom-workeroptions-credentials>credentials</code> can be used to
     specify how <var>scriptURL</var> is fetched, but only if <code id=dedicated-workers-and-the-worker-interface:dom-workeroptions-type><a href=#dom-workeroptions-type>type</a></code> is set to "<code>module</code>".</ul>
   <dt><code><var>worker</var>.<span id=dom-worker-terminate>terminate</span>()</code><dd>Aborts <var>worker</var>'s associated global environment.<dt><code><var>worker</var>.<span id=dom-worker-postmessage>postMessage</span>(<var>message</var> [, <var>transfer</var> ])</code><dt><code><var>worker</var>.<span id=dom-worker-postmessage-options>postMessage</span>(<var>message</var> [, { <span>transfer</span> } ])</code><dd><p>Clones <var>message</var> and transmits it to <var>worker</var>'s global environment.
   <var>transfer</var> can be passed as a list of objects that are to be transferred rather than
   cloned.</dl>

  

  <div class=example>

   <p>The <code id=dedicated-workers-and-the-worker-interface:dom-worker-postmessage><a href=#dom-worker-postmessage>postMessage()</a></code>
   method's first argument can be structured data:</p>

   <pre><code class='js'>worker<c- p>.</c->postMessage<c- p>({</c->opcode<c- o>:</c-> <c- t>&apos;activate&apos;</c-><c- p>,</c-> device<c- o>:</c-> <c- mf>1938</c-><c- p>,</c-> parameters<c- o>:</c-> <c- p>[</c-><c- mf>23</c-><c- p>,</c-> <c- mf>102</c-><c- p>]});</c-></code></pre>

  </div>

  


  <h5 id=shared-workers-and-the-sharedworker-interface><span class=secno>10.2.4.3</span> Shared workers and the <code id=sharedworker>SharedWorker</code> interface<a href=#shared-workers-and-the-sharedworker-interface class=self-link></a></h5><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker title="The SharedWorker interface represents a specific kind of worker that can be accessed from several browsing contexts, such as several windows, iframes or even workers. They implement an interface different than dedicated workers and have a different global scope, SharedWorkerGlobalScope.">SharedWorker</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>29+</span></span><span class="safari yes"><span>Safari</span><span>16+</span></span><span class="chrome yes"><span>Chrome</span><span>5+</span></span><hr><span class="opera yes"><span>Opera</span><span>10.6+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge unknown"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>Internet Explorer</span><span>No</span></span><hr><span class="firefox_android yes"><span>Firefox Android</span><span>33+</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>16+</span></span><span class="chrome_android no"><span>Chrome Android</span><span>No</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android no"><span>Samsung Internet</span><span>4.0–5.0</span></span><span class="opera_android no"><span>Opera Android</span><span>11–14</span></span></div></div></div>

  

  <dl class=domintro><dt><code><var>sharedWorker</var> = new <span id=dom-sharedworker>SharedWorker</span>(<var>scriptURL</var> [, <var>name</var> ])</code><dd><p>Returns a new <code id=shared-workers-and-the-sharedworker-interface:sharedworker><a href=#sharedworker>SharedWorker</a></code> object. <var>scriptURL</var> will be fetched and
   executed in the background, creating a new global environment for which <var>sharedWorker</var>
   represents the communication channel. <var>name</var> can be used to define the <span>name</span> of that global environment.<dt><code><var>sharedWorker</var> = new <a href=#dom-sharedworker id=shared-workers-and-the-sharedworker-interface:dom-sharedworker>SharedWorker</a>(<var>scriptURL</var> [, <var>options</var> ])</code><dd>
    <p>Returns a new <code id=shared-workers-and-the-sharedworker-interface:sharedworker-2><a href=#sharedworker>SharedWorker</a></code> object. <var>scriptURL</var> will be fetched and
    executed in the background, creating a new global environment for which <var>sharedWorker</var>
    represents the communication channel.</p>

    <p><var>options</var> can contain the following values:</p>

    <ul><li><p><code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-name><a href=#dom-workeroptions-name>name</a></code> can be used to define the <span>name</span> of that global environment.<li><p><code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-type><a href=#dom-workeroptions-type>type</a></code> can be used to load the new global
     environment from <var>scriptURL</var> as a JavaScript module, by setting it to the value "<code>module</code>".<li><p><code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-credentials><a href=#dom-workeroptions-credentials>credentials</a></code> can be used to specify
     how <var>scriptURL</var> is fetched, but only if <code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-type-2><a href=#dom-workeroptions-type>type</a></code> is set to "<code>module</code>".</ul>

    <p>Note that attempting to construct a shared worker with <var>options</var> whose <code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-type-3><a href=#dom-workeroptions-type>type</a></code>, or <code id=shared-workers-and-the-sharedworker-interface:dom-workeroptions-credentials-2><a href=#dom-workeroptions-credentials>credentials</a></code> values mismatch those
    of an existing shared worker with the same <span>constructor URL</span> and <span>name</span>, will cause the returned
    <var>sharedWorker</var> to fire an <code id=shared-workers-and-the-sharedworker-interface:event-error><a href=indices.html#event-error>error</a></code> event and not connect
    to the existing shared worker.</p>
   <dt><code><var>sharedWorker</var>.<span id=dom-sharedworker-port>port</span></code><dd><p>Returns <var>sharedWorker</var>'s <code>MessagePort</code> object which can be used to
   communicate with the global environment.</dl>

  


  <h4 id=navigator.hardwareconcurrency><span class=secno>10.2.5</span> Concurrent hardware capabilities<a href=#navigator.hardwareconcurrency class=self-link></a></h4>

  

  <dl class=domintro><dt><code><var>self</var>.<span>navigator</span>.<span id=dom-navigator-hardwareconcurrency>hardwareConcurrency</span></code><dd><p>Returns the number of logical processors potentially available to the user agent.</dl>

  

  <h3 id=apis-available-to-workers><span class=secno>10.3</span> APIs available to workers<a href=#apis-available-to-workers class=self-link></a></h3>

  


  <h4 id=the-workernavigator-object><span class=secno>10.3.1</span> The <code id=workernavigator>WorkerNavigator</code> interface<a href=#the-workernavigator-object class=self-link></a></h4><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerNavigator title="The WorkerNavigator interface represents a subset of the Navigator interface allowed to be accessed from a Worker. Such an object is initialized for each worker and is available via the self.navigator property.">WorkerNavigator</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>12.1+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>12.1+</span></span></div></div></div>

  

  

  <div>

  <p>The <code id=the-workernavigator-object:workernavigator><a href=#workernavigator>WorkerNavigator</a></code> interface implements a subset of the <code>Navigator</code>
  interface, consisting of the following APIs:</p>

  <ul class=brief><li><a href=system-state.html#client-identification>Client identification</a><li><a href=system-state.html#language-preferences>Language preferences</a><li><a href=system-state.html#navigator.online>Browser state</a><li><a href=#navigator.hardwareconcurrency>Concurrent hardware capabilities</a></ul>

  </div>

  <h4 id=worker-locations><span class=secno>10.3.2</span> The <code id=workerlocation>WorkerLocation</code> interface<a href=#worker-locations class=self-link></a></h4><div class="mdn-anno wrapped"><button onclick=toggleStatus(this) class=mdn-anno-btn><b title="Support in all current engines." class=all-engines-flag>✔</b><span>MDN</span></button><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerLocation/toString title="The toString() stringifier method of a WorkerLocation object returns a string containing the serialized URL for the worker's location. It is a synonym for WorkerLocation.href.">WorkerLocation/toString</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>15+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android yes"><span>WebView Android</span><span>37+</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>14+</span></span></div></div><div class=feature><p><a href=https://developer.mozilla.org/en-US/docs/Web/API/WorkerLocation title="The WorkerLocation interface defines the absolute location of the script executed by the Worker. Such an object is initialized for each worker and is available via the WorkerGlobalScope.location property obtained by calling self.location.">WorkerLocation</a><p class=all-engines-text>Support in all current engines.<div class=support><span class="firefox yes"><span>Firefox</span><span>3.5+</span></span><span class="safari yes"><span>Safari</span><span>4+</span></span><span class="chrome yes"><span>Chrome</span><span>4+</span></span><hr><span class="opera yes"><span>Opera</span><span>12.1+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span><hr><span class="edge yes"><span>Edge (Legacy)</span><span>12+</span></span><span class="ie yes"><span>Internet Explorer</span><span>10+</span></span><hr><span class="firefox_android unknown"><span>Firefox Android</span><span>?</span></span><span class="safari_ios yes"><span>Safari iOS</span><span>5+</span></span><span class="chrome_android unknown"><span>Chrome Android</span><span>?</span></span><span class="webview_android unknown"><span>WebView Android</span><span>?</span></span><span class="samsunginternet_android unknown"><span>Samsung Internet</span><span>?</span></span><span class="opera_android yes"><span>Opera Android</span><span>12.1+</span></span></div></div></div>

  

  <p>The <code id=worker-locations:workerlocation><a href=#workerlocation>WorkerLocation</a></code> interface is like the <code>Location</code> interface,
  but lacks the <code id=worker-locations:dom-location-assign><a href=nav-history-apis.html#dom-location-assign>assign()</a></code>, <code id=worker-locations:dom-location-replace><a href=nav-history-apis.html#dom-location-replace>replace()</a></code>, <code id=worker-locations:dom-location-reload><a href=nav-history-apis.html#dom-location-reload>reload()</a></code>,
  and <code id=worker-locations:dom-location-ancestororigins><a href=nav-history-apis.html#dom-location-ancestororigins>ancestorOrigins</a></code> members.</p>

  


  <nav><a href=web-messaging.html>← 9.3 Cross-document messaging</a> — <a href=index.html>Table of Contents</a> — <a href=worklets.html>11 Worklets →</a></nav>
